그냥 하는 노트와 메모장

BOJ 1600 - 말이 되고픈 원숭이 본문

Solved problems

BOJ 1600 - 말이 되고픈 원숭이

coloredrabbit 2020. 11. 13. 16:15

BOJ 1600 - 말이 되고픈 원숭이

[분류 - BFS]

 

[풀이]

  말처럼 뛰는 동작은 k를 정확히 1만큼을 올리기 때문에 k+1과 k는 인접해있다. 
  따라서 k+1번째에 특정 좌표 (y, x)에 도달했다면 그 값이 곧 최소 동작이 된다.

 

vi[k][y][x] - y행 x열에 k번만 말처럼 뛰어서 도달할 수 있는 동작 수의 최소값

 

  BFS 특성상 진행하려는 방향에 대해 정확히 1만큼 증가시키고 vi[k+1][y][x]에 도달할 수 있는 위치가 (y1, x1), (y2, x2)일 때,


1. vi[k][y1][x1] > vi[k][y2][x2]
  BFS 큐에 들어가는 좌표는 (y2, x2)가 더 우선순위를 가진다.

2. vi[k][y1][x1] <= vi[k][y2][x2]
  BFS 큐에 들어가는 좌표는 (y1, x1)가 더 우선순위를 가진다.


따라서 최초 방문은 곧 최소 동작 수를 나타냄을 알 수 있다.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAX_H = 200, MAX_K = 51;
struct _d { int k, y, x; };
int main() {
    int i, j, K, H, W, vi[MAX_K][MAX_H][MAX_H] = {}, b[MAX_H][MAX_H], dy[2][8] = { {0,0,1,-1}, {-1,-2,-2,-1,1,2,2,1} }, dx[2][8] = { {1,-1,0,0}, {-2,-1,1,2,2,1,-1,-2} }, n[] = { 4,8 }, answer = 1e9;
    queue<_d> q;
    scanf("%d%d%d", &K, &W, &H);
    for (i = 0; i < H; i++) for (j = 0; j < W; j++)
        scanf("%d", &b[i][j]);
    vi[K][0][0] = 1;
    q.push({ K, 0, 0 });
    while (!q.empty()) {
        auto u = q.front(); q.pop();
        if (u.y == H - 1 && u.x == W - 1)
            answer = min(answer, vi[u.k][u.y][u.x] - 1);
        for (i = 0; i < 2; i++) {
            int tk = u.k - i;
            if (u.k - i >= 0)
                for (j = 0; j < n[i]; j++) {
                    int ty = u.y + dy[i][j], tx = u.x + dx[i][j];
                    if (0 <= ty && ty < H && 0 <= tx && tx < W && vi[tk][ty][tx] == 0 && b[ty][tx] == 0) {
                        vi[tk][ty][tx] = vi[u.k][u.y][u.x] + 1;
                        q.push({ tk, ty, tx });
                    }
                }
        }
    }
    printf("%d", answer == 1e9 ? -1 : answer);
    return 0;
}

'Solved problems' 카테고리의 다른 글

BOJ 1053 - 팰린드롬 공장  (0) 2020.11.13
BOJ 2618 - 경찰차  (0) 2020.11.13
BOJ 8902 색상의 길이  (0) 2020.07.01
BOJ 1226 국회  (0) 2020.06.25
BOJ 1128 피보나치 냅색  (0) 2020.06.22
Comments