반응형

https://www.acmicpc.net/problem/21610

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int N, M, A[51][51];
bool cloudCheck[51][51];
vector<pair<int, int>> cloudPosition;

int dx[8] = {0, -1, -1, -1, 0, 1, 1, 1};
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1};

void cloudMove(int d, int s) {
  for (int i = 0; i < cloudPosition.size(); i++) {
    int x = cloudPosition[i].first;
    int y = cloudPosition[i].second;

    int nx = (x + dx[d] * s) % N;
    nx = nx <= 0 ? nx + N : nx;

    int ny = (y + dy[d] * s) % N;
    ny = ny <= 0 ? ny + N : ny;

    cloudCheck[nx][ny] = 1;
    A[nx][ny]++;

    cloudPosition[i].first = nx;
    cloudPosition[i].second = ny;
  }
}

void waterCopyBug() {
  for (int i = 0; i < cloudPosition.size(); i++) {
    int x = cloudPosition[i].first;
    int y = cloudPosition[i].second;

    int cnt = 0;
    for (int j = 1; j < 8; j += 2) {
      int nx = x + dx[j];
      int ny = y + dy[j];

      if (nx <= 0 || nx > N || ny <= 0 || ny > N)
        continue;

      if (A[nx][ny] > 0)
        cnt++;
    }

    A[x][y] += cnt;
  }
}

void makeCloud() {
  cloudPosition.clear();
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      if (!cloudCheck[i][j] && A[i][j] >= 2) {
        cloudPosition.push_back({i, j});
        A[i][j] -= 2;
      }
    }
  }

  memset(cloudCheck, 0, sizeof(cloudCheck));
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);

  cin >> N >> M;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      cin >> A[i][j];
    }
  }

  cloudPosition.push_back({N, 1});
  cloudPosition.push_back({N, 2});
  cloudPosition.push_back({N - 1, 1});
  cloudPosition.push_back({N - 1, 2});

  for (int i = 1; i <= M; i++) {
    int d, s;
    cin >> d >> s;
    cloudMove(d - 1, s);
    waterCopyBug();
    makeCloud();
  }

  int ans = 0;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      ans += A[i][j];
    }
  }

  cout << ans;
  return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/21608

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int N, num, seat[21][21], student[401][4];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

bool isInLikeStudent(int cur, int x, int y) {
  for (int i = 0; i < 4; i++) {
    if (student[cur][i] == seat[x][y])
      return true;
  }
  return false;
}

void sitDownOneByOne(int cur) {
  int resX = -1, resY = -1;
  //여기가 중요한 포인트! 0 / 0인 경우가 정답이 될 수 있다
  int maxLikeStudents = -1, maxEmpties = -1;

  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      int likeStudents = 0;
      int empty = 0;

      if (seat[i][j] > 0)
        continue;
      for (int k = 0; k < 4; k++) {
        int nx = i + dx[k];
        int ny = j + dy[k];
        if (nx <= 0 || nx > N || ny <= 0 || ny > N)
          continue;
        if (seat[nx][ny] == 0) {
          empty++;
        } else if (isInLikeStudent(cur, nx, ny)) {
          likeStudents++;
        }
      }

      if (likeStudents > maxLikeStudents) {
        maxLikeStudents = likeStudents;
        maxEmpties = empty;
        resX = i;
        resY = j;
      } else if (likeStudents == maxLikeStudents) {
        if (empty > maxEmpties) {
          maxEmpties = empty;
          resX = i;
          resY = j;

        } else if (empty == maxEmpties) {
          if (resX == i && resY > j) {
            resY = j;
          } else if (resX > i) {
            resX = i;
            resY = j;
          }
        }
      }
    }
  }

  seat[resX][resY] = cur;
}

void Input() {
  cin >> N;
  num = N * N;
  for (int i = 1; i <= num; i++) {
    int cur;
    cin >> cur;
    for (int j = 0; j < 4; j++) {
      cin >> student[cur][j];
    }
    sitDownOneByOne(cur);
  }
}

int calAns() {
  int ans = 0;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {

      int myFriends = 0;
      for (int k = 0; k < 4; k++) {
        int nx = i + dx[k];
        int ny = j + dy[k];

        if (nx <= 0 || nx > N || ny <= 0 || ny > N)
          continue;
        if (isInLikeStudent(seat[i][j], nx, ny)) {
          myFriends++;
        }
      }
      if (myFriends == 1) {
        ans += 1;
      } else if (myFriends == 2) {
        ans += 10;
      } else if (myFriends == 3) {
        ans += 100;
      } else if (myFriends == 4) {
        ans += 1000;
      }
    }
  }

  return ans;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  Input();
  cout << calAns() << '\n';

  return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/20058

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

#include <bits/stdc++.h>

using namespace std;

int N,rows, Q,L, A[64][64];
int dx[4] = {1,0,-1,0};
int dy[4] = {0,1,0,-1};

void TurnBox(int x, int y, int len){
    int retBox[len][len];

    for(int i=0; i<len; i++) {
        for (int j = 0; j < len; j++) {
            retBox[j][len-1-i] = A[x+i][y+j];
        }
    }

    for(int i=0; i<len; i++) {
        for (int j = 0; j < len; j++) {
            A[x+i][y+j] = retBox[i][j];
        }
    }

}


void Turn(int _L){
    int box = pow(2,N) / pow(2, _L);
    int len = pow(2,_L);

    for(int i=0; i<box ;i++){
        for(int j=0; j<box; j++) {
            int x = i*len;
            int y = j*len;

            TurnBox(x,y,len);
        }
    }
}

void Melt(){
    vector<pair<int,int> > willMelt;

    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            int cnt = 0;
            if(A[i][j]==0) continue;
            for(int k=0; k<4; k++){
                int nx = i + dx[k];
                int ny= j +dy[k];
                if(nx<0||nx>=rows||ny<0||ny>=rows) continue;
                if(A[nx][ny] > 0) cnt++;
            }
            if(cnt <3){
                willMelt.push_back({i,j});
            }
        }
    }

    for(int i=0; i<willMelt.size();i++){
        A[willMelt[i].first][willMelt[i].second]--;
    }
}

void Round(int _L){
    Turn(_L);
    Melt();
}


void Input();
int Count(){
    int sum = 0;
    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            sum += A[i][j];
        }
    }
    return sum;
}

int getMax(){
    bool ch[64][64] = {0};
    int ans = 0;
    queue<pair<int,int> > Q;

    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            if(!ch[i][j] && A[i][j]>0){
                ch[i][j] = 1;
                int cnt = 1;
                Q.push({i,j});

                while(!Q.empty()){
                    auto cur = Q.front(); Q.pop();

                    for(int k=0; k<4; k++){
                        int nx = cur.first + dx[k];
                        int ny= cur.second +dy[k];
                        if(nx<0||nx>=rows||ny<0||ny>=rows) continue;
                        if(ch[nx][ny] || A[nx][ny]==0) continue;
                        Q.push({nx,ny});
                        ch[nx][ny] = 1;
                        cnt++;

                    }
                }

                ans = max(ans, cnt);
            }
        }
    }


    return ans;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();
    cout << Count() << '\n';
    cout << getMax() << '\n';

}

void Input() {
    cin >> N >> Q;
    rows = pow(2,N);
    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            cin >> A[i][j];
        }
    }
    for(int i=0; i<Q; i++){
        cin >> L;
        Round(L);
    }
}
반응형
반응형
https://www.acmicpc.net/problem/20057
 

20057번: 마법사 상어와 토네이도

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을

www.acmicpc.net

1.문제설명

토네이도의 이동 방법은 단순 반복이기 때문에

반복문으로 구현할 수 있다.

 

토네이도에 따라 모래가 이동하는 것을 잘 구현해야 한다.

항상 모래가 퍼지는 방법은 동일한데

토네이도의 이동방향에 따라 다르다.

 

토네이도의 이동방향을 기준으로

현재 이동방향과 수직에 놓여있는지,

아니면 현재 이동방향의 2칸 앞에 있는지

현재 토네이도가 이동한 위치와 이동했던 방향을 기준으로

함수를 만들면 4방향에 대해서 모두 처리해주지 않아도 된다.

 

 

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;

int N, sum, sand[500][500];

void Input();


int dx[4] = {0, 1, 0, -1};
int dy[4] = {-1, 0, 1, 0};

bool inSand(int x, int y) {
    return (x >= 1 && x <= N && y >= 1 && y <= N);
}

void flySand(int x, int y, int dir) {
    int nx = x + dx[dir] * 2;
    int ny = y + dy[dir] * 2;
    int sum = 0;

    int num = int(sand[x][y] * 0.05);
    sum += num;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }

    //수직

    num = int(sand[x][y] * 0.07);
    sum += num;
    nx = x + dx[(dir + 1) % 4];
    ny = y + dy[(dir + 1) % 4];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.07);
    sum += num;
    nx = x + dx[(dir + 3) % 4];
    ny = y + dy[(dir + 3) % 4];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.02);
    sum += num;
    nx = x + dx[(dir + 1) % 4] * 2;
    ny = y + dy[(dir + 1) % 4] * 2;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.02);
    sum += num;
    nx = x + dx[(dir + 3) % 4] * 2;
    ny = y + dy[(dir + 3) % 4] * 2;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    //수직

    num = int(sand[x][y] * 0.1);
    sum += num;
    nx = x + dx[(dir + 1) % 4] + dx[dir];
    ny = y + dy[(dir + 1) % 4] + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.1);
    sum += num;
    nx = x + dx[(dir + 3) % 4] + dx[dir];
    ny = y + dy[(dir + 3) % 4] + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    //수직\

    num = int(sand[x][y] * 0.01);
    sum += num;
    nx = x + dx[(dir + 1) % 4] - dx[dir];
    ny = y + dy[(dir + 1) % 4] - dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.01);
    sum += num;
    nx = x + dx[(dir + 3) % 4] - dx[dir];
    ny = y + dy[(dir + 3) % 4] - dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }

    nx = x + dx[dir];
    ny = y + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += sand[x][y] - sum;
    }

    sand[x][y] = 0;

}


void tornadoMove() {
    int x = N / 2 + 1, y = N / 2 + 1;
    int dir = 0;
    int moveBlocks = 1;
    int cnt = 0;

//    while(!(x==1 && y==1)){
    while (1) {
        for (int i = 0; i < moveBlocks; i++) {
            x += dx[dir];
            y += dy[dir];
            flySand(x, y, dir);

            if (x == 1 && y == 1) return;
        }
        cnt++;
        dir = (dir + 1) % 4;
        if (cnt == 2) {
            moveBlocks++;
            cnt = 0;
        }

    }
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);


    Input();
    tornadoMove();

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            sum -= sand[i][j];
        }
    }

    cout << sum << '\n';
}

void Input() {
    cin >> N;

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cin >> sand[i][j];
            sum += sand[i][j];
        }
    }
}
반응형
반응형

https://www.acmicpc.net/problem/20056

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

www.acmicpc.net

1. 문제설명

구현함에 있어서 문제의 단계를 꼼꼼히 보아야하는 문제

각 파이어볼이 모두 이동한 후에 합쳐져야 하므로

현재 배열에 존재하는 파이어볼을 기준으로

새로운 배열에 파이어볼의 이동을 담아야한다.

 

 

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;
int N, M, K;

struct fireBall {
    int m, s, d;
};

int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};

vector<fireBall> arr[51][51];
void Input();

void move() {
    vector<fireBall> nextState[51][51];
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (arr[i][j].size() > 0) {
                for (auto k: arr[i][j]) {
                    int nx = (i + dx[k.d] * k.s) % N;
                    int ny = (j + dy[k.d] * k.s) % N;
                    if (nx <= 0) nx += N;
                    if (ny <= 0) ny += N;
                    nextState[nx][ny].push_back({k.m, k.s, k.d});
                }
            }
        }
    }

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (nextState[i][j].size() > 1) {
                int sumM = 0;
                int sumS = 0;
                bool dirSame = true;
                int dir = nextState[i][j][0].d % 2;
                for (auto k: nextState[i][j]) {
                    if (k.d % 2 != dir) {
                        dirSame = false;
                    }
                    sumS += k.s;
                    sumM += k.m;
                }

                int newM = sumM / 5;
                int newS = sumS / nextState[i][j].size();

                //new fireball 4
                nextState[i][j].clear();
                if (newM <= 0) continue;

                int newDir = 0;
                if (!dirSame) newDir = 1;

                for (int k = 0; k < 4; k++) {
                    nextState[i][j].push_back({newM, newS, newDir});
                    newDir += 2;
                }
            }
        }
    }
    swap(nextState, arr);
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();
    for (int i = 0; i < K; i++) {
        move();
    }

    int ans = 0;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            for (auto k: arr[i][j]) {
                ans += k.m;
            }
        }
    }
    cout << ans << '\n';
}

void Input() {
    cin >> N >> M >> K;
    for (int i = 0; i < M; i++) {
        int r, c, m, d, s;
        cin >> r >> c >> m >> s >> d;
        arr[r][c].push_back({m, s, d});
    }
}

 

반응형
반응형

https://www.acmicpc.net/problem/20055

 

20055번: 컨베이어 벨트 위의 로봇

길이가 N인 컨베이어 벨트가 있고, 길이가 2N인 벨트가 이 컨베이어 벨트를 위아래로 감싸며 돌고 있다. 벨트는 길이 1 간격으로 2N개의 칸으로 나뉘어져 있으며, 각 칸에는 아래 그림과 같이 1부

www.acmicpc.net

1. 문제설명

벨트가 회전함에 따라

각 벨트 번호의 내구도가 한칸씩 옮겨지고 로봇또한 한칸씩 옮겨지는 것을 구현하고,

벨트위에 있는 로봇을 옮길 수 있는지 확인한 후 한 칸씩 옮기는 것을 구현해야하는 문제이다.

 

이를 구현하기 위해

벨트의 번호에 따른 내구도를 나타내는 배열을 만들고

벨트의 번호에 따라 로봇이 있는지 여부를 나타내는 배열을 만들어서

회전시키는 것을 구현하면 된다.

 

단순 회전은 큐를 이용하면 쉽겠지만

이 문제에서는 각 로봇에 대해 접근을 해야하기 때문에

차라리 배열을 이용하는 것이 괜찮은 것 같다.

큐를 이용하면 회전을 빠르게 구현 할 수 있겠지만

결국 각 벨트 번호에 대한 로봇의 여부를 구하기 위해 인덱스접근하는데 O(n)이 필요하기 떄문이다.

 

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;
int N, K;
void Input();

int durability[202];
bool robots[101];


void beltRotate(){
    int beltLast = durability[2*N];
    for(int i=2*N; i>1; i--){
        durability[i] = durability[i-1];
    }
    durability[1] = beltLast;

    for(int i=N; i>=1; i--){
        robots[i] = robots[i-1];
    }
    robots[N] = 0;


    for(int i=N-1; i>=1; i--){
        if(robots[i]){
            if(durability[i+1] > 0 && !robots[i+1]){
                durability[i+1]--;
                robots[i+1] = 1;
                robots[i] = 0;

                if(i+1 ==N) robots[i+1] =0;
            }
        }
    }

    if(durability[1] > 0){
        robots[1] = 1;
        durability[1]--;
    }
}

bool check(){
    int cnt = 0;
    for(int i=1; i<=2*N; i++){
        if(durability[i]==0){
            cnt++;
        }
    }

    return cnt >= K;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    Input();

    int turn = 1;
    while(1){
        beltRotate();
        if(check()){
            cout << turn << '\n';
            return 0;
        }
        turn++;
    }
}



void Input() {
    cin >> N >> K;
    for(int i=1; i<=2*N; i++){
        cin >> durability[i];
    }
}
반응형
반응형

https://www.acmicpc.net/problem/19238

 

19238번: 스타트 택시

첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다. 다

www.acmicpc.net

1.문제설명

택시가 손님을 정해진 위치에 데려다 주면서 이동한 거리를 바탕으로 연료의 양을 조건에 따라 계산해야하는 문제이다.

 

이 문제를 풀기 위해 BFS가 여러번 쓰인다.

 

 

1. 첫번째로 택시가 모든 손님과 모든 손님의 도착점으로 이동할 수 있는지 검사해야한다.

벽으로 경로가 끊어져 있을 수 있기 때문에 Flood Fill 방식으로 계산한다.

 

2. 두번째로 가까이 있는 손님을 구하기 위해 Flood Fill 방식으로 다시

현재 택시의 위치와 손님과의 거리를 구한다.

이때 주의해야할 점은 손님을 발견하자마자 BFS를 종료하면 안되고,

손님을 발견하더라도 전체 맵을 다 돌 때까지 BFS를 실행해야한다.

 

map의 크기가 작기 때문에 시간초과에 걸리지 않는다.

이렇게 해야하는 이유는 먼저 모든 손님에 대하여 각 손님까지의 거리를 구한 후

거리가 동일한 경우 행과 열의 숫자를 보고 손님을 정해야하기 때문이다.

만약 BFS를 돌다 손님 하나를 발견하자마자 종료한다면

같은 거리에 위치했지만 행과 열 정보에서 우선순위를 지니는 손님을 탐색하지 못한다.

 

 

3. 세번째는 손님 ---- 도착점 사이의 거리를 구하기 위해 BFS를 사용한다.

Map의 중간 중간 벽이 존재하기 때문에 BFS나 DFS로 거리를 구해야 한다.

 

이러한 세가지 기능을 구현해주면 문제를 해결할 수 있다.

 


2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;
int N, M, F; //F : 초기연료
bool arr[21][21]; //벽
int stx, sty; //driver 시작점
int guestInfo[403][4]; // guest마다 시작x,y 종점x,y
bool checkGuestEnd[403];

int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

void Input();

bool gameCheck(int _stx, int _sty) { //flood Fill -> driver로부터 guest 시작점,종점 경로가 연결 되어 있는지확인
    bool ch[21][21] = {0};
    queue<pair<int, int> > Q;

    ch[_stx][_sty] = 1;
    Q.push({_stx, _sty});

    while (!Q.empty()) {
        auto cur = Q.front();
        Q.pop();

        for (int i = 0; i < 4; i++) {
            int nx = cur.first + dx[i];
            int ny = cur.second + dy[i];

            if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
            if (ch[nx][ny] || arr[nx][ny]) continue;
            Q.push({nx, ny});
            ch[nx][ny] = 1;
        }
    }

    for (int i = 1; i <= M; i++) {
        int x = guestInfo[i][0];
        int y = guestInfo[i][1];
        int nx = guestInfo[i][2];
        int ny = guestInfo[i][3];

        if (ch[x][y] == 0 || ch[nx][ny] == 0) {
            return false;
        }
    }
    return true;
}

pair<int,int> chooseGuest(int _stx, int _sty){
    int ch[21][21] = {0};
    queue<pair<int, int> > Q;

    ch[_stx][_sty] = 1;
    Q.push({_stx, _sty});

    while (!Q.empty()) {
        auto cur = Q.front();
        Q.pop();

        for (int i = 0; i < 4; i++) {
            int nx = cur.first + dx[i];
            int ny = cur.second + dy[i];

            if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
            if (ch[nx][ny] > 0 || arr[nx][ny]) continue;
            Q.push({nx, ny});
            ch[nx][ny] = ch[cur.first][cur.second] + 1;

        }
    }

    int minDist = 100000;
    int nextGuest = -1;

    for(int i=1; i<=M; i++){
        if(checkGuestEnd[i]) continue;

        int curDist = ch[guestInfo[i][0]][guestInfo[i][1]];
        if( curDist< minDist){
            nextGuest = i;
            minDist = curDist;
        }
        else if(curDist == minDist){
            if(guestInfo[nextGuest][0] > guestInfo[i][0]){
                nextGuest = i;
            }
            else if(guestInfo[nextGuest][0] == guestInfo[i][0]){
                if(guestInfo[nextGuest][1] > guestInfo[i][1]){
                    nextGuest = i;
                }
            }
        }
    }

    return {nextGuest, minDist-1};
}

int calDistance(int _stx, int _sty, int enx, int eny){
    int ch[21][21] = {0};
    queue<pair<int, int> > Q;

    ch[_stx][_sty] = 1;
    Q.push({_stx, _sty});

    while (!Q.empty()) {
        auto cur = Q.front();
        Q.pop();

        for (int i = 0; i < 4; i++) {
            int nx = cur.first + dx[i];
            int ny = cur.second + dy[i];

            if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
            if (ch[nx][ny] > 0 || arr[nx][ny]) continue;
            Q.push({nx, ny});
            ch[nx][ny] = ch[cur.first][cur.second] + 1;
            if(nx==enx && ny==eny) break;
        }
    }

    return ch[enx][eny]- 1;
}

bool allGuestGoHome(){
    for(int i=1; i<=M; i++){
        if(!checkGuestEnd[i]) return false;
    }
    return true;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    Input();


    //벽 때문에 깃발이나 손님한테 갈 수 없는 경우
    if (!gameCheck(stx,sty)) {
        cout << -1 << '\n';
        return 0;
    }


    while(!allGuestGoHome()) {
        auto nextGuest = chooseGuest(stx, sty);
        int guest = nextGuest.first;
        int toGuestDist = nextGuest.second;
        int toFlagDist = calDistance(guestInfo[guest][0], guestInfo[guest][1], guestInfo[guest][2], guestInfo[guest][3]);


        if(F<toGuestDist + toFlagDist){
            cout << -1 << '\n';
            return 0;
        }
        else{
            //guest 집에감, 연료 동기화
            checkGuestEnd[guest] = 1;
            F = F - toGuestDist + toFlagDist;

            //driver 이동
            stx = guestInfo[guest][2];
            sty = guestInfo[guest][3];
        }
    }

    cout << F << '\n';
}


void Input() {
    cin >> N >> M >> F;

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cin >> arr[i][j];
        }
    }
    //driver start
    cin >> stx >> sty;

    for (int i = 1; i <= M; i++) {
        cin >> guestInfo[i][0] >> guestInfo[i][1] >> guestInfo[i][2] >> guestInfo[i][3]; //start x,y / end x, y
    }


}
반응형
반응형

https://www.acmicpc.net/problem/19237

 

19237번: 어른 상어

첫 줄에는 N, M, k가 주어진다. (2 ≤ N ≤ 20, 2 ≤ M ≤ N2, 1 ≤ k ≤ 1,000) 그 다음 줄부터 N개의 줄에 걸쳐 격자의 모습이 주어진다. 0은 빈칸이고, 0이 아닌 수 x는 x번 상어가 들어있는 칸을 의미

www.acmicpc.net

1.문제설명

구현해야할 부분 단위가 많은 시뮬레이션 문제이다.

 

각 부분에 대하여 기능을 잘 분리하고

올바른 순서로 기능을 수행해야 문제를 해결 할 수 있다.

 

주의해야할 점은

모든 상어가 동시에 움직이고 동시에 냄새를 뿌린다는 점이다.

 

즉 상어가 움직이면서 냄새를 뿌리도록 구현하면

잘못된 구현이다.

 

 

 

크게 구현해야할 것은

1. 턴 마다 상어 움직이기

2. 냄새 뿌리기

3. 1번 상어만 남아있는지 확인하기

 

1번을 구현하기 위해서 부분 문제로

각 상어마다 방향정보를 바탕으로

이동해야할 위치와 방향을 구해야한다.

 

이 때 모든 상어는 동시에 움직인다는 조건을 지니므로

상어의 위치를 각 상어마다 옮기고 바로 적용해주는 것이 아니라

현재 위치와 다음 턴의 위치를 구분 짓기 위해서

다른 배열을 하나 두어서 체크를 해주는 것도 중요한 포인트다.

 

 


 

2.문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int N, M, K;
int sharkState[500][3];
int dirPriority[500][5][5];
//20X20 (smell, shark)
int smell[30][30][2];

int dx[5] = {0, -1, 1, 0, 0};
int dy[5] = {0, 0, 0, -1, 1};


void Input();


void sharkNextState(int sharkNum, int &x, int &y, int &d) {
    int curX = x;
    int curY = y;
    int curD = d;

    //먼저 현재 방향으로 이동 가능한지 체크
    int nx = -1;
    int ny = -1;
    int nd = -1;

    for (int i = 1; i <= 4; i++) {
        nd = dirPriority[sharkNum][curD][i];
        nx = curX + dx[nd];
        ny = curY + dy[nd];

        if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
        if (smell[nx][ny][0] > 0) continue;
        x = nx;
        y = ny;
        d = nd;
        return ;
    }

    //네 방향모두 냄새로 가득 차있으니 자신의 냄새있는 칸 찾기
    for (int i = 1; i <= 4; i++) {
        nd = dirPriority[sharkNum][curD][i];
        nx = curX + dx[nd];
        ny = curY + dy[nd];

        if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
        if (smell[nx][ny][1] != sharkNum) continue;
        x = nx;
        y = ny;
        d = nd;
        return;
    }
}


void allSharkCheck() {
    bool nextMap[30][30] = {0};
    for (int i = 1; i <= M; i++) {
        int curX = sharkState[i][0];
        int curY = sharkState[i][1];
        int curD = sharkState[i][2];

        //죽은 상어 제외
        if (curX < 0) continue;
        sharkNextState(i, curX, curY, curD);

        //번호 작은 상어 이미 존재
        if (nextMap[curX][curY]) {
            sharkState[i][0] = -1;
            continue;
        }

        sharkState[i][0] = curX;
        sharkState[i][1] = curY;
        sharkState[i][2] = curD;
        nextMap[curX][curY] = 1;
    }
}


bool gameEndCheck() {
    //1번 상어 살아 있고
    if (sharkState[1][0] < 0) return false;
    //다른 상어 모두 죽었을 때
    for (int i = 2; i <= M; i++) {
        if (sharkState[i][0] > 0) {
            return false;
        }
    }
    return true;
}

void spreadSmell(){
    for (int i = 1; i <= M; i++) {
        int curX = sharkState[i][0];
        int curY = sharkState[i][1];
        if (curX < 0) continue;
        smell[curX][curY][0] = K;
        smell[curX][curY][1] = i;
    }
}


void decrementSmell(){
    for(int i=1; i<=N;i++){
        for(int j=1; j<=N; j++){
            if(smell[i][j][0]>0){
                smell[i][j][0]--;
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();
    for (int i = 1; i <= 1000; i++) {
        spreadSmell();
        allSharkCheck();
        if (gameEndCheck()) {
            cout << i << '\n';
            return 0;
        }
        decrementSmell();
    }
    cout << -1 << '\n';
}


void Input() {
    cin >> N >> M >> K;
    //x, y
    for (int x = 1; x <= N; x++) {
        for (int y = 1; y <= N; y++) {
            int sk;
            cin >> sk;

            if (sk > 0) {
                sharkState[sk][0] = x;
                sharkState[sk][1] = y;
            }
        }
    }
    //dir
    for (int i = 1; i <= M; i++) {
        cin >> sharkState[i][2];
    }

    for (int i = 1; i <= M; i++) {
        for (int j = 1; j <= 4; j++) {
            for (int k = 1; k <= 4; k++) {
                cin >> dirPriority[i][j][k];
            }
        }
    }
}
반응형

+ Recent posts