PS
백준 1600번 말이 되고픈 원숭이
남마허
2020. 2. 19. 13:13
https://www.acmicpc.net/problem/1600
1600번: 말이 되고픈 원숭이
첫째 줄에 자연수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있는 곳으로는 이동할 수 없다. 시작점과 도착점은 항상 평지이다. W와 H는 1이상 200이하의 자연수이고, K는 0이상 30이하의 정수이다.
www.acmicpc.net
<접근방법>
bfs 문제 입니다.
전형적인 문제와 조금 다른 점이 있습니다.
원숭이가 같은 (y, x) 라는 좌표에 있더라도 능력이 몇 번 남았느냐에 따라 남은 결과가 달라진다는 것 입니다.
(y, x)에서 능력이 1번 남았을 때와 0번 남았을 때를 비교해보면 바로 알 수 있지요.
그래서 단순히 좌표만으로 중복체크를 한다면 안된다는 것 입니다.
그럼 중복체크를 어떻게 할까요?
같은 좌표와 같은 능력 횟수를 가지고 있다면 결과도 같겠죠?
그러므로 좌표에다가 능력까지 포함한 중복체크를 해줘야합니다.
이것은 중복체크배열을 3차원으로 하면 됩니다.
<코드>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
struct point {
int y, x, cnt, time;
};
int k, n, m, map[200][200];
int dy[12] = { 1, -1, 0, 0,-2, -1, 1, 2, 2, 1, -1, -2 };
int dx[12] = { 0, 0, 1, -1, 1, 2 ,2, 1, -1, -2, -2, -1 };
bool visit[200][200][30] = { false, };
int bfs() {
queue<point> q;
q.push({0, 0, k, 0});
visit[0][0][k] = true;
while (!q.empty()) {
point t = q.front();
q.pop();
if (t.y == n - 1 && t.x == m - 1) return t.time;
for (int i = 0; i < 12; i++) {
int ty, tx, tcnt = t.cnt, ttime = t.time + 1;
if (i >= 4) {
if (t.cnt == 0) break;
tcnt -= 1;
}
ty = t.y + dy[i];
tx = t.x + dx[i];
if (ty < 0 || ty >= n || tx < 0 || tx >= m) continue;
if (visit[ty][tx][tcnt] || map[ty][tx] == 1) continue;
q.push({ty, tx, tcnt, ttime});
visit[ty][tx][tcnt] = true;
}
}
return -1;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> k;
cin >> m >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
}
}
cout << bfs() << '\n';
return 0;
}
<느낀 점>
-스택, 메모리, 힙 영역
반응형