Post

[코드트리] 마법의 숲 탐색

문제 링크

마법의 숲 탐색

풀이

히든케이스 때문에 어려웠던 문제. 실제로 시험장에서 풀었으면 통과하지 못했을 것 같다. 이 문제는 시뮬레이션이기는 하지만 골렘이 숲을 벗어난 경우를 처리하는 것이 매우 까다로웠다. 일일히 골렘이 숲을 벗어난 경우를 찾아서 예외 처리를 하기 보다는 그냥 배열의 세로 크기를 +3 해준 상태로 시뮬레이션을 돌렸다.

1
map = new int[R+3][C];

세로 인덱스 0 ~ 2는 숲 밖의 영역을 의미하게 된다.

1
if(y<=3) return false;

만약 정령의 위치가 0 ~ 3인 경우 골렘이 숲 밖에 있기 때문에 배열을 초기화하여 골렘을 밖으로 뺐다.

1
answer += center_move() - 2;

또한, 현재 위치를 더할 때도 본래 값에서 2를 빼줘야 한다.(3빼고 인덱스는 0부터 시작이므로 1을 더하기 때문)

나는 출구를 그냥 음수로 표현했다.

1
2
3
   1
1  1  1
  -1

위는 남쪽이 출구인 경우이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(!q.isEmpty()){
  pos cur = q.poll();
  int num = map[cur.y][cur.x];
  max = Math.max(cur.y,max);
  for(int i=0;i<4;i++){
      int ny = dy[i]+cur.y, nx = dx[i]+cur.x;
      if(!(0<=ny && ny<R+3 && 0<=nx && nx<C)) continue;
      if(map[ny][nx] == 0 || visit[ny][nx]) continue; 
      if(num < 0 || map[ny][nx] == num || map[ny][nx] == - num){
          q.add(new pos(ny,nx));
          visit[ny][nx] = true;
      }
  }
}

이렇게 짜면 현재 정령의 위치가 음수인 경우에는 어디든 갈 수 있고(0 제외), 양수인 경우에는 자신과 같거나 자신의 값에 -1을 곱한 값에만 접근하는 조건으로 문제의 요구사항을 만족시킬 수 있다.

총 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import java.io.*;
import java.util.*;

public class Main {
    static int R,C,K;
    static int[][] map;
    static int cury, curx;
    static int[] dy = {-1,1,0,0}, dx = {0,0,-1,1};
    private static class pos{
        int y, x;
        pos(int y, int x){
            this.y = y;
            this.x = x;
        }
    }

    static void clean(int y, int x){
        map[y+1][x]= map[y-1][x]= map[y][x+1]= map[y][x-1]= map[y][x] = 0;
    }
    static boolean check(int y, int x){
        if(y+1 == R + 3 || x - 1 < 0 || x + 1 == C) return false; // 범위 밖으로 나가는 경우
        if(map[y+1][x]!=0 || map[y-1][x]!=0 || map[y][x+1]!=0 || map[y][x-1]!=0 || map[y][x]!=0) return false; // 다른 블록이 있는 경우
        return true;
    }

    static void move(int y,int x,int dir, int num){
        map[y+1][x]= map[y-1][x]= map[y][x+1]= map[y][x-1]= map[y][x] = num;
        if(dir == 0) map[y-1][x] = -num;
        else if(dir == 1) map[y][x+1] = -num;
        else if(dir == 2) map[y+1][x] = -num;
        else map[y][x-1] = -num;
    }

    public static boolean down(int ci, int dir, int num){
        int y = 1, x = ci;
        while(true){
            clean(y,x);
            if(check(y+1,x)){
                move(y+1,x,dir,num);
                y++;
            }
            else if(check(y,x-1) && check(y+1,x-1)){
                move(y+1,x-1,(dir+3)%4,num);
                y++;
                x--;
                dir = (dir+3)%4;
            }
            else if(check(y,x+1) && check(y+1,x+1)){
                move(y+1,x+1,(dir+1)%4,num);
                y++;
                x++;
                dir = (dir+1)%4;
            }else{
                move(y,x,dir,num);
                break;
            }
        }

        curx = x;
        cury = y;
        if(y<=3) return false;
        return true;
    }

    static int center_move(){
        Queue<pos> q = new LinkedList<>();
        q.add(new pos(cury,curx))
        boolean[][] visit = new boolean [R+3][C];
        visit[cury][curx] = true;
        int max = cury;
        
        while(!q.isEmpty()){
            pos cur = q.poll();
            int num = map[cur.y][cur.x];
            max = Math.max(cur.y,max);
            for(int i=0;i<4;i++){
                int ny = dy[i]+cur.y, nx = dx[i]+cur.x;
                if(!(0<=ny && ny<R+3 && 0<=nx && nx<C)) continue;
                if(map[ny][nx] == 0 || visit[ny][nx]) continue; 
                if(num < 0 || map[ny][nx] == num || map[ny][nx] == - num){
                    q.add(new pos(ny,nx));
                    visit[ny][nx] = true;
                }
            }
        }
        return max;
    }

    public static void main(String[] args) throws IOException {
        // 여기에 코드를 작성해주세요.
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] input = br.readLine().trim().split(" ");
        R = Integer.parseInt(input[0]);
        C = Integer.parseInt(input[1]);
        K = Integer.parseInt(input[2]);
        map = new int[R+3][C];
        int answer = 0;
        for(int num=1;num<=K;num++){
            input = br.readLine().trim().split(" ");
            int ci = Integer.parseInt(input[0]) - 1;
            int di = Integer.parseInt(input[1]);
            if(!down(ci,di,num)){
                map = new int[R+3][C];
            }else answer += center_move() - 2;
        }
        System.out.println(answer);
    }
}
This post is licensed under CC BY 4.0 by the author.