알고리즘

[Algorithm/Java] 백준 17500 국경

지수쓰 2022. 2. 7. 18:41
반응형

https://www.acmicpc.net/problem/17500

 

17500번: 국경

만약 조건을 만족하는 국경이 존재하지 않는다면 첫 번째 줄에 "no" 를 출력하고 더 이상 아무것도 출력하지 않아야 합니다. 조건을 만족하는 국경이 존재한다면 첫 번째 줄에 "yes" 를 출력하고

www.acmicpc.net

 

보통 배열은 칸으로 움직이는데 이 문제는 꼭지점,선분을 이어서 움직여야해서 처음에 어떻게해야할지 고민이었다.

일단 N이 최대가 4여서 모든 경우를 다 해보면 될 것 같았다.

N*N 배열을 (2*N+1)*(2*N+1)로 늘려서 나라가 되는 부분과 국경과 될수 있는 부분을 모두 배열로 치고 나라 부분을 경계로 두고 목적지 까지 갈 수 있는 모든 경로를 백트래킹으로 탐색했다.

나라부분이 벽인(visit[i][j]=1) 도로 dfs 문제 이런느낌으로 생각했다. 

 

국경을 visit[i][j]=1, 나라부분을 visit[i][j]=2로 두고 

백트래킹으로 끝지점에 도착했을 때의 상태에서 visit[i][j]=2인데 '.'이 아닌 곳에서 checkdfs를 다시 돌려줬다.

국경내부에 있는 갈 수 있는 모든곳을 탐색해서 나라부분이 '.'이 아닌 다른 알파벳이면 false ..

checkdfs부분에서 새로운 visit배열을 써야해서 tmp에 담아줬다.

 

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Border{
    static int N;
    static int M;
    static char[][] map;
    static char[][] newMap;
    static int[][] visit;
    static int[] dx = {-1,1,0,0};
    static int[] dy = {0,0,-1,1};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = 2*N+1;
        map = new char[N][N];
        newMap = new char[2*N+1][2*N+1];
        visit = new int[2*N+1][2*N+1];
        for(int i=0; i<N; i++){
            String str = br.readLine();
            for(int j=0; j<N; j++){
                map[i][j] = str.charAt(j);
            }
        }
        // 입력받은 값으로 newMap, visit을 생성해줌 
        for(int i=0; i<M; i++) {
            for(int j=0; j<M; j++){
                if((i%2==0) && j%2==0) newMap[i][j]='+';
            }
        }
        for(int i=0; i<N; i++){
            for(int j=0; j<N; j++){
                newMap[2*i+1][2*j+1] = map[i][j];
                visit[2*i+1][2*j+1]=2;
            }
        }


        //모든 경우를 탐색해서 [2n][2N]에 도착할때 확인
        visit[0][0]=1;
        boolean result = dfs(0,0);
        
        // 결과출력 
        if(result) {
            System.out.println("yes");
            for(int i=0; i<4*N+3; i++) System.out.print("#");
            System.out.println("");
            for(int i=0; i<M; i++){
                System.out.print("#");
                if(i%2==0) {
                    for(int j=0; j<M; j++){
                        if(newMap[i][j]=='+') System.out.print('+');
                        else if(visit[i][j]==1) {
                            System.out.print("---");
                        }
                        else System.out.print("   ");
                    }
                }
                else {
                    for (int j = 0; j <M; j++) {
                        if (visit[i][j] == 2) System.out.print(" "+newMap[i][j]+" ");
                        else if (visit[i][j] == 1) {
                            System.out.print("|");
                        }
                        else System.out.print(" ");
                    }
                }
                System.out.println("#");
            }
            for(int i=0; i<4*N+3; i++) System.out.print("#");
        }
        else {
            System.out.println("no");
        }
    }
    
    
    
    public static boolean dfs(int x, int y) {
        if( x==2*N && y==2*N) {
          // 끝점에 도착하면 check
            return check();
        }
      // 끝점이 아니라면 갈 수 있는 경로 탐색
        for(int i=0 ;i<4; i++){
            int A = x+dx[i];
            int B = y+dy[i];
            if(A>=0 &&B>=0 && A<=2*N && B<=2*N && visit[A][B]==0) {
              //백트래킹으로 모든 경로 확인 
                visit[A][B]=1;
              // 탐색으로 하나라도 true를 찾았다면 리턴
                if(dfs(A,B)) return true;
                visit[A][B]=0;
            }
        }
        return false;
    }
    public static boolean check(){
      // 만들어낸 국경이 조건에 부합하는지 확인 
        int [][] tmp = new int[M][M];
        for(int i=0; i<M; i++){
            for(int j=0; j<M; j++){
                tmp[i][j] = visit[i][j];
            }
        }
        for(int i=0; i<M; i++){
            for(int j=0; j<M; j++){
                if(tmp[i][j]==2 && newMap[i][j]!='.') {
                  // 나라를 발견하면 국경에 쌓여있는 부분에 해당 나라와 같은것만 있는지 확인. 다른게 있으면 바로 false 리턴 
                    if(checkdfs(i, j, tmp, newMap[i][j])==false)
                        return false;
                }
            }
        }
        return true;
    }
    public static boolean checkdfs(int x, int y, int[][] tmp, char c){
        tmp[x][y]=1;
        for(int i=0; i<4; i++){
            int A= x+dx[i];
            int B=y+dy[i];
            if(A>=0 &&B>=0 && A<=2*N && B<=2*N && tmp[A][B]!=1 ) {
              // .이 아닌 나라가 c와 다르면 false
              if(A%2==1 && B%2==1 && newMap[A][B]!='.' && newMap[A][B]!=c)
                    return false;
                else if(checkdfs(A,B,tmp,c)==false)
                    return false;
            }
        }
        return true;
    }
}

 

틀렸던부분

- 나라가 될 수 있는 부분을 visit[i][j]=2로 지정해놨었는데 '.'인경우에는 조건문으로 확인하지않고 어떤 알파벳값일경우에만 dfs탐색하거나 조건문 확인했어야했다.