dfs + dp문제
단순 dfs문제가 아니었던 문제.
사이클이 발생하지 않는다면 한 번 돌 때 nm번만 돌면 되니까 시간복잡도가 O(nm)이 아닐까 하고 나이브하게 생각했다.
그래서 이게 왜 골드2지? 생각하다가,, 역시나 시간초과가 발생했다.
한 번 돌면 nm인건 맞는데, 문제는 한 번만 돌지 않는다는 거다.
1에서 출발하여 네 방향으로 갈 수 있고, 그 다음 칸에서 또 네 방향으로 갈 수 있고 ...
그렇기에 최악의 경우 시간복잡도는 O(4^nm)이다. 단순 완전탐색으로는 문제를 풀 수 없으므로 다른 방법을 고안해야 한다.
DP를 사용하여 이미 계산한 결과는 빠르게 리턴하도록 만들어주면 시간복잡도를 줄일 수 있다.
dp[x][y]는 (x, y)위치에서 가능한 최대 움직임 수이다.
사이클 탐색은 이미 visit한 곳을 방문했다면 사이클이 존재한다는 뜻이므로 -1을 출력하고 끝내면 된다.
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, arr[51][51], dp[51][51];
bool visit[51][51], flag = true;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
// DP를 사용하지 않을 경우 O(4^NM)
int dfs(int x, int y) {
if (dp[x][y]) return dp[x][y];
visit[x][y] = true;
for(int i = 0; i < 4; i++) {
int nx = x + dx[i] * arr[x][y];
int ny = y + dy[i] * arr[x][y];
if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
if (arr[nx][ny] == 0) continue;
if (visit[nx][ny]) {
flag = false;
return 0;
};
dp[x][y] = max(dp[x][y], dfs(nx, ny) + 1);
}
visit[x][y] = false;
return dp[x][y];
}
int main() {
ios_base::sync_with_stdio(false); cin.tie(NULL);
char c;
cin >> n >> m;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cin >> c;
if (c == 'H') arr[i][j] = 0;
else arr[i][j] = c - '0';
}
}
int ans = dfs(1, 1);
if (flag) cout << ans + 1;
else cout << -1;
}