[백준1103] 게임 (C++)

유후·2025년 2월 23일
0

백준

목록 보기
68/69

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;
}
profile
배우고 익힌 것을 세상에 말하기

0개의 댓글