티스토리 뷰

풀이

문제를 제대로 안읽어서 순서대로 방문하기 문제인데, 순서대로 방문하지 않고 풀어서 틀렸습니다.. 

처음 생각했을 때는 n=4이므로 전체 가능한 칸의 수는 16이 되고, DFS로 백트래킹 할 경우, 맥시멈 4 * 3^15 재귀 호출되고, 각 재귀 호출에서 4방향 탐색을 위해 for문을 도니까 4 * 3^15 * 4 ~= 2.3억이 나와서 시간 안에 부족하지 않나 생각했습니다. 

n이 작아서 예시를 들어서 해보니, 대부분 각 칸에서 다음으로 진행 가능한 경우가 3가지가 되지 않고 pruning 되어서 통과 될 것이라 판단하였습니다.

 

또 BFS로 풀이한다면, 풀이가 조금 더 복잡해질 것이라고 판단했습니다. 현재까지 이동한 경로에 따라, 다음 이동 할 수 있는 칸이 달라지기 때문입니다.

 

위 부분을 유의하여 순서대로 방문하는 코드를 작성하면 다음과 같습니다.

import java.io.*;
import java.util.*;

public class Main {

    public static class Pair {
        int y, x;

        public Pair(int y, int x) {
            this.y = y;
            this.x = x;
        }
    }

    static int n, m;
    static int[][] board;
    static Pair[] spot;
    static int[] dy = {-1, 0, 1, 0};
    static int[] dx = {0, -1, 0, 1};
    static int spotIdx;
    static int ans;
    public static void main(String[] args) throws IOException 
    {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        board = new int[n+1][n+1];
        spot = new Pair[m];
        for(int i=1; i<=n; i++) {
            s = br.readLine().split(" ");
            for(int j=1; j<=n; j++) {
                board[i][j] = Integer.parseInt(s[j-1]);
            }
        }

        for(int i=0; i<m; i++) {
            s = br.readLine().split(" ");
            int y = Integer.parseInt(s[0]);
            int x = Integer.parseInt(s[1]);
            spot[i] = new Pair(y, x);
        }

        boolean[][] vis = new boolean[n+1][n+1];
        vis[spot[0].y][spot[0].x] = true;
        dfs(spot[0].y, spot[0].x, 1, vis);
        System.out.println(ans);
    }

    public static void dfs(int y, int x, int spotIdx, boolean[][] vis) {

        // System.out.println(y + " " + x + " " + ans);
        
        if(spotIdx == m) {
            ans++;
            return;
        }

        for(int dir=0; dir<4; dir++) {
            int ny = y + dy[dir];
            int nx = x + dx[dir];
            if(ny < 1 || ny > n || nx < 1 || nx > n) continue;
            if(board[ny][nx] == 1 || vis[ny][nx]) continue;

            vis[ny][nx] = true;
            if(ny == spot[spotIdx].y &&  nx == spot[spotIdx].x) {
                dfs(ny, nx, spotIdx+1, vis);   
            } else {
                dfs(ny, nx, spotIdx, vis);
            }
            vis[ny][nx] = false;
        }
    }
}

풀이 설명

1. Spot에 입력으로 들어온 m개의 지점을 순서대로 넣습니다.

2. 현재 방문한 지점에서 다음 지점까지 경로를 탐색합니다. (1번 지점 -> 2번 지점, 2번 지점 -> 3번 지점 ...)

3. 다음 지점에 도달할 시 spotIdx를 +1 하여 재귀 호출합니다. (SpotIdx는 현재 도착해야 할 지점의 인덱스입니다.) => dfs(ny, nx, spotIdx+1, vis)

4. 이동한 칸이 지점이 아닌 경우, spotIdx를 증가시키지 않고 탐색을 진행합니다. => dfs(ny, nx, spotIdx, vis)

4. 만약 spotIdx가 m이 되면(마지막 지점까지 방문했으면) 경로의 수를 1증가 시킵니다.

5. backtracking을 방문 표시를 지우고 다음 경로를 계속 탐색합니다.

'알고리즘 > 브루트포스' 카테고리의 다른 글

C++ 1248 Guess  (0) 2023.07.31
C++ 14501 퇴사  (0) 2023.07.29
C++ 10972 다음 순열  (0) 2023.07.29
C++ 1748 수 이어 쓰기 1  (0) 2023.07.27
C++ 14500 테트로미노  (0) 2023.07.24
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday