알고리즘 풀이/백준(Boj)

백준(BOJ) 2933번 미네랄

100win10 2019. 9. 20. 15:57

문제 : https://www.acmicpc.net/problem/2933



문제

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

동굴은 R행 C열로 나타낼 수 있으며, R×C칸으로 이루어져 있다. 각 칸은 비어있거나 미네랄을 포함하고 있으며, 네 방향 중 하나로 인접한 미네랄이 포함된 두 칸은 같은 클러스터이다.

창영은 동굴의 왼쪽에 서있고, 상근은 오른쪽에 서있다. 두 사람은 턴을 번갈아가며 막대기를 던진다. 막대를 던지기 전에 던질 높이를 정해야 한다. 막대는 땅과 수평을 이루며 날아간다.

막대가 날아가다가 미네랄을 만나면, 그 칸에 있는 미네랄은 모두 파괴되고 막대는 그 자리에서 이동을 멈춘다.

미네랄이 파괴된 이후에 남은 클러스터가 분리될 수도 있다. 새롭게 생성된 클러스터가 떠 있는 경우에는 중력에 의해서 바닥으로 떨어지게 된다. 떨어지는 동안 클러스터의 모양은 변하지 않는다. 클러스터는 다른 클러스터나 땅을 만나기 전까지 게속해서 떨어진다. 클러스터는 다른 클러스터 위에 떨어질 수 있고, 그 이후에는 합쳐지게 된다.

동굴에 있는 미네랄의 모양과 두 사람이 던진 막대의 높이가 주어진다. 모든 막대를 던지고 난 이후에 미네랄 모양을 구하는 프로그램을 작성하시오.


풀이 :


막대를 하나씩 던질때마다 DFS를 통해 한번에 이동할 미네랄들을 group에 저장한다.


그리고 low 배열을 만들어서 각 열마다 가장 큰 행을 넣어주자. 즉 가장 밑에있는 미네랄을 넣어주는 것.


그리고 각 열마다 가장 큰 행들이 얼마나 밑으로 내려갈수 있는지 정한다. 그 후 그중 최소만큼 옮긴다.


막대를 던진 횟수 만큼 반복한다.



코드 ( C++ )




#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
char cave[100][100];
int branch[100];
int N;
int R, C;
int visited[100][100];
const int dy[4] = { 1,-1,0,0 };
const int dx[4] = { 0,0,1,-1 };
vector<pair<int, int>> group;
void DFS(int y, int x)
{
if (cave[y][x] == '.') return;
if (visited[y][x]) return;
visited[y][x] = true;
group.push_back({ y,x });
for (int i = 0; i < 4; ++i)
{
int ny = y + dy[i];
int nx = x + dx[i];
if (0 <= nx && nx < C && 0 <= ny && ny < R)
DFS(ny, nx);
}
}
void solve()
{
memset(visited, 0, sizeof(visited));
for (int a = 0; a < R; ++a)
for (int b = 0; b < C; ++b)
{
if (visited[a][b]) continue;
if (cave[a][b] == '.') continue;
group.clear();
DFS(a, b);
vector<int> low(C, -1);
for (int i = 0; i < group.size(); ++i)
{
auto &p = group[i];
//각 열마다 가장 밑에있는 행을 찾는다
low[p.second] = max(low[p.second], p.first);
//옮길점들 이므로 '.'로 바꿔주자
cave[p.first][p.second] = '.';
}
//얼마나 밑으로 옮길지 결정
int lowmove = R;
for (int i, j = 0; j < C; ++j) {
if (low[j] == -1) continue;
i = low[j];
// 내려갈수 있을때까지 내려간다
while (i < R && cave[i][j] == '.') {
++i;
}
lowmove = min(lowmove, i - low[j] - 1);
}
for (int i = 0; i < group.size(); ++i) {
auto &p = group[i];
p.first += lowmove;
cave[p.first][p.second] = 'x';
visited[p.first][p.second] = true;
}
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cin >> R >> C;
for (int i = 0; i < R; ++i)
for (int j = 0; j < C; ++j)
{
cin >> cave[i][j];
}
cin >> N;
for (int i = 0; i < N; ++i)
{
int num;
cin >> num;
branch[i] = R - num;
}
// 한번 맞치고 한번 DFS 검사
for (int i = 0; i < N; ++i)
{
int height = branch[i];
if (i % 2 == 0)
{
for (int j = 0; j < C; ++j)
{
if (cave[height][j] == 'x') {
cave[height][j] = '.';
break;
}
}
}
else
{
for (int j = C - 1; j >= 0; --j)
{
if (cave[height][j] == 'x') {
cave[height][j] = '.';
break;
}
}
}
// DFS 검사
solve();
}
//cave 출력
for (int i = 0; i < R; ++i) {
for (int j = 0; j < C; ++j)
cout << cave[i][j];
cout << "\n";
}
return 0;
}
view raw .cpp hosted with ❤ by GitHub