[백준] 2933_미네랄 (자바 풀이)

문제

 

2933번: 미네랄

창영과 상근은 한 동굴을 놓고 소유권을 주장하고 있다. 두 사람은 막대기를 서로에게 던지는 방법을 이용해 누구의 소유인지를 결정하기로 했다. 싸움은 동굴에서 벌어진다. 동굴에는 미네랄

www.acmicpc.net

풀이

이 문제의 풀이를 요약하자면 아래와 같다. 

 

1. 왼쪽, 오른쪽 번갈아서 미네랄 파괴

2. 미네랄 파괴 후 공중에 떠있는 클러스터 BFS로 찾기

3. 공중에 떠있는 클러스터들을 아래로 내리기

 

먼저, 1번을 구현하는 것은 쉽다. 단순히 홀수, 짝수를 나누어 왼쪽에서부터 탐색, 오른쪽에서부터 탐색해서 'x'를 '.'으로 바꿔주기만 하면 된다.

 

2번을 구현하는 것은 조금 까다롭다. 우선 '공중에 떠있다'라는 것은 클러스터가 땅에 붙어있지 않다는 것을 의미한다. 이것은 BFS를 통해 찾을 수 있는데, 가장 아래 땅에서부터 BFS탐색을 진행하면 땅에 붙어있는 클러스트들을 찾을 수 있다. 따라서 BFS를 통해 땅에 붙어있는 클러스트들을 visited[][] 배열을 이용해 방문처리를 해주고, 이후 방문처리가 안되어있는 클러스트를 따로 저장하면 된다.

 

3번은 2번에서 따로 저장한 공중에 떠있는 클러스트들의 세로 좌표를 1씩 올리고 범위를 벗어나지 않는지만 체크하면 된다. 모든 좌표를 수정한 후 map[][]의 원소를 'x'로 수정해주면 완료이다.

 

코드

 

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main {
 
    static int r,c,n;
    static char[][] map;
    static boolean[][] visited;
    static Queue<Node> q = new LinkedList<>();
    static int[] dx = {0,0,1,-1};
    static int[] dy = {1,-1,0,0};
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        r = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
        
        map = new char [r][c];
        
        for (int i = 0; i < r; i++) {
            map[i] = br.readLine().toCharArray();
        }
        
        n = Integer.parseInt(br.readLine());
        st = new StringTokenizer(br.readLine());
        
        for (int i = 0; i < n; i++) {
            int h = r-Integer.parseInt(st.nextToken());
           
            breakMineral(h,i);    // 미네랄 파괴
            bfs();    // 클러스터 내리기
        }
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < r; i++) {
            sb.append(map[i]);
            sb.append("\n");
        }
        System.out.print(sb.toString());
    }
    
    static void bfs() {
        visited = new boolean[r][c];
        ArrayList<Node> cluster = new ArrayList<>();
        
        // 땅에 붙어있는 클러스터들을 방문처리
        for (int j = 0; j < c; j++) {
            if(map[r-1][j] =='.' || visited[r-1][j])
                continue;
            
            visited[r-1][j] = true;
            q.add(new Node(r-1, j));
            
            while(!q.isEmpty()) {
                Node cur = q.poll();
                
                for (int i = 0; i < 4; i++) {
                    int nx = cur.x + dx[i];
                    int ny = cur.y + dy[i];
                    
                    if(!isRange(nx, ny) || visited[nx][ny] || map[nx][ny] =='.')
                        continue;
                    
                    visited[nx][ny] = true;
                    q.add(new Node(nx, ny));
                }
            }
        }
        
        // 공중에 떠 있는 클러스터 찾기 == 방문처리가 안되어 있는 클러스터 찾기
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if(!visited[i][j] && map[i][j] == 'x') {
                    map[i][j] = '.';
                    cluster.add(new Node(i, j));
                }
            }
        }
        
        // 공중에 뜬 클러스터가 없으면 return
        if(cluster.isEmpty()) {    
            return;
        }
        
        // 클러스터 내리기
        boolean down = true;
        while(down) {
            for(Node node : cluster) {
                int nx = node.x +1;
                int ny = node.y;
                
                if(!isRange(nx, ny) || map[nx][ny] == 'x') {
                    down = false;
                    break;
                }
            }
            if(down) {
                for(Node node : cluster) {
                    node.x++;
                }
            }
        }
        
        // map 원소 변경
        for(Node node : cluster) {
            map[node.x][node.y] = 'x';
        }
        
    }
    
    static boolean isRange(int x, int y) {
        if( x < 0 || x >= r || y < 0 || y >= c) return false;
        return true;
    }
    
    static void breakMineral (int row, int i) {
        if(i % 2 == 0) {
            for (int j = 0; j < c; j++) {
                if(map[row][j] == 'x') {
                    map[row][j] = '.';
                    break;
                }
            }    
        }
        else {
            for (int j = c-1; j >= 0; j--) {
                if(map[row][j] == 'x') {
                    map[row][j] = '.';
                    break;
                }
            }
        }
    }
    
    static class Node {
        int x;
        int y;
        
        Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
}
cs

결과

result

 

반응형

댓글

Designed by JB FACTORY