알고리즘/BOJ(C++)

[백준 / BOJ] 2933 :: 미네랄

쿠마쿠마34 2021. 2. 6. 22:56
반응형

www.acmicpc.net/problem/2933

 

2933번: 미네랄

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

www.acmicpc.net

문제 설명 : 

막대기를 한번은 왼쪽에서 오른쪽으로, 다른 한번은 오른쪽에서 왼쪽으로 던질 것이다.

이때 각 방향으로 탐색해서 오면서 처음 만나는 미네랄을 캘 것이다.(미네랄이 있는 곳이 0 처리됨)

 

미네랄은 클러스터(군집)이 있다. 상하좌우로 연결된 미네랄은 같인 미네랄 클러스터이다.

미네랄을 캐면서 하나의 미네랄이 없어지는데, 이 때 기존에 연결되어 있던 클러스터가 서로 분리 될 수도 있다.

그러면 그 두 클러스터 중 하나의 클러스터는 아래로 떨어지게 된다.

 

떨어지는 것을 멈추게 되는 조건은 두개 중 하나이다.

다른 클러스터를 만나거나, 바닥에 부딪히거나.

 

이렇게 모든 작업을 끝내고 최종적인 map의 모습을 출력하면 된다.

 

 

문제 해결:

우선, N번의 작업을 수행하는 것을 시뮬레이션 시켜야 한다.

 

각 작업을 했을 때 처음으로 판단해야 하는 것은, 미네랄을 캤을 때 두 클러스터가 분리되었는지 분리 되지 않았는지를 판단해야 한다. 분리 기준에는 두 개가 있다. 서로 다른 클러스터로 분리된 경우 / 공중에서 뜬 경우

이를 위해 우리는 미네랄 하나를 캐고(map에서 0처리) , 그 후 다시 군집을 만든다.

군집을 만든다는 개념은 마치 아파트단지에 번호를 붙이는 느낌이다.

이런식으로 이웃한 클러스터마다 고유의 번호를 붙여준다.

 

우리는 캔 미네랄의 위치를 0으로 만들고, 매번 다시 이 번호를 계산하여 매기면 된다.

이 번호를 매긴 후, 캐어진 미네랄 위치를 기준으로 상하좌우 클러스터 번호를 탐색한다. 상하좌우 중 클러스터 번호가 다른 경우가 있다면 이는 분리된 클러스터가 존재하는 경우이다.

 

그렇다면 공중에서 뜬 경우는? 

작업하는 위치가 1번인 경우, 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
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
 
int R, C, N;
vector<int> job;
int map[101][101];
int dx[4= { -1,1,0,0 };
int dy[4= { 0,0,-1,1 };
bool visited[101][101];
 
void print() {
    for (int i = R; i >= 1; i--) {
        for (int j = 1; j <= C; j++) {
            cout << map[i][j] << ' ';
        }
        cout << endl;
    }
    cout << endl;
}
void dfs(int x, int y, int num) {
    queue<pair<intint > > q;
    q.push({ x,y });
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            if (nx > R || nx <1 || ny > C || ny < 1continue;
            if (map[nx][ny] != 0 && visited[nx][ny] == false) {
                map[nx][ny] = num;
                visited[nx][ny] = true;
                q.push({ nx,ny });
            }
        }
    }
}
void makeCluster() {
    for (int i = 0; i < 101; i++) {
        for (int j = 0; j < 101; j++) {
            visited[i][j] = false;
        }
    }
    int cnt = 1;//clsuter count number;
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            if (map[i][j] != 0 && visited[i][j] == false) {//미네랄이 있는 위치
                map[i][j] = cnt;
                dfs(i, j, cnt);
                cnt++;
            }
        }
    }
}
int main() {
    cin >> R >> C;
    for (int i = R; i >= 1; i--) {
        string s;
        cin >> s;
        for (int j = 0; j < C; j++) {
            if (s[j] == '.') map[i][j + 1= 0;
            else if (s[j] == 'x') map[i][j + 1= -1;
        }
    }
    for (int i = 1; i <= C; i++) {
        map[0][i] = 102;
    }//바닥 설정
 
    cin >> N;
    for (int i = 0; i < N; i++) {
        int tmp;
        cin >> tmp;
        job.push_back(tmp);
    }
    makeCluster();
 
 
    for (int cnt = 0; cnt < N; cnt++) {
        //cout << job[cnt] << " : " << endl;
        //print();
 
        bool flag = false;
        int fall_cluster;
        int now = 0;
        if (cnt % 2 == 0) { //왼쪽에서 오른쪽으로 
            for (int j = 1; j <= C; j++) {
                if (map[job[cnt]][j] != 0) {
                    now = map[job[cnt]][j];
                    map[job[cnt]][j] = 0;//미네랄 캠
                    makeCluster();
                    for (int k = 0; k < 4; k++) {
                        int nx = job[cnt] + dx[k];
                        int ny = j + dy[k];
                        if (nx > R || nx <1 || ny > C || ny < 1continue;
                        if (map[nx][ny] != 0) {
                            if (now != map[nx][ny]) {//클러스터가 분리된 경우
                                //cout << i << " : " << "분리됨!" << endl;
                                fall_cluster = map[nx][ny];
                                flag = true;
                            }
                        }
                    }
                    break;
                }
            }
 
 
        }
        else {//오른쪽에서 왼쪽으로 
            for (int j = C; j >= 1; j--) {
                if (map[job[cnt]][j] != 0) {
                    now = map[job[cnt]][j];
                    map[job[cnt]][j] = 0;//미네랄 캠
                    makeCluster();
                    for (int k = 0; k < 4; k++) {
                        int nx = job[cnt] + dx[k];
                        int ny = j + dy[k];
                        if (nx > R || nx <1 || ny > C || ny < 1continue;
                        if (map[nx][ny] != 0) {
                            if (now != map[nx][ny]) {//클러스터가 분리된 경우
                                flag = true;
                                fall_cluster = map[nx][ny];
 
                                //cout << i<<" : " <<"분리됨!" << endl;
                            }
                        }
                    }
                    break;
                }
            }
        }
 
        if (!flag && job[cnt] == 1) {//공중에서 떴는지 확인
            bool tmp_flag = false;
            for (int j = 1; j <= C; j++) {
                if (map[1][j] == now) {
                    tmp_flag = true;
                    break;
                }
            }
            if (!tmp_flag) {
                flag = true;
                fall_cluster = now;
            }
        }
 
        if (flag) {//클러스터가 분리된 경우 
            //cout<< "분리됨" << endl;
            int bottom;
            int move = 101;//아래로 평행이동 해야하는 칸의 수 
            int tmp = 0;
            for (int i = R; i >= 1; i--) {
                for (int j = 1; j <= C; j++) {
                    if (map[i][j] == fall_cluster) {
                        bottom = i;
                        break;
                    }
                }
            }
            //cout << "bottom : " << bottom << endl;
            for (int i = 1; i <=R ; i++) {
                for (int j = 1; j <= C; j++) {
                    if (map[i][j] == fall_cluster) {
                        int tmp = 1;
                        while (i - tmp >= 0) {
                            if (map[i - tmp][j] != 0 && map[i-tmp][j] != fall_cluster) {
                                move = min(tmp, move);
                                break;
                            }
                            else tmp++;
                        }
                    }
                }
            }
            
            //cout << "움직여야 하는 칸의 수 : " << move<< endl;
            move--;
            for (int i = 1; i <= R; i++) {
                for (int j = 1; j <= C; j++) {
                    if (map[i][j] == fall_cluster) {
                        if (map[i - move][j] == 0) {
                            map[i - move][j] = fall_cluster;
                            map[i][j] = 0;
                        }
                    }
                }
            }
            makeCluster();
        }
        
    }
    for (int i = R; i >= 1; i--) {
        for (int j = 1; j <= C; j++) {
            if (map[i][j] == 0)
                cout << ".";
            else
                cout << "x";
        }
        cout << endl;
    }
 
 
}
cs
반응형