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

 

풀이 아이디어를 정리해보자.

 

문제 진행 과정

1. 막대 던진다


2. 미네랄 제거

   (→ 해당 row의 leftmost/rightmost 'x' 제거)

// Step 1. Throw stick, destroy mineral
if (left){
    for (char& c : board[h]){
        if (c == 'x') {
            c = '.';
            break;
        }
    }
    left = false;
}
else{
    for(int idx = C-1; idx >= 0; idx--){
        char& c = board[h][idx];
        if (c == 'x') {
            c = '.';
            break;
        }
    }
    left = true;
}

 

3. 클러스터 정리 

  • 클러스터 판별
    (→ Union-Find로 각 'x'의 집합 정해주기)
// Step 2. Identify clusters
DisjointSet g(R * C);

auto to_pos = [&](int x, int y) { return (R * C - 1) - (x * C + y); };
auto boundary_0 = [&](int x, int y) {return 0 <= x && x < R && 0 <= y && y < C; };

// ★ Order is important (from bottom to top) - to ensure bottom groups are propagated
for (int x = R - 1; x >= 0; x--) for (int y = C - 1; y >= 0; y--) {
    if (board[x][y] == '.') continue;

    for (int i = 0; i < 4; i++) {
        int xn = x + "1210"[i] - '1'; // E S W N
        int yn = y + "2101"[i] - '1';

        if (!boundary_0(xn, yn) || board[xn][yn] == '.') continue;

        g.Union(to_pos(x, y), to_pos(xn, yn));
    }
}

 

  • 바닥과 연결되어있지 않은 클러스터 떨어뜨리기
    (→ 바닥 집합에 포함되지 않은 'x'를 떨어뜨릴 클러스터로 판단;
         한꺼번에 떨어뜨리기 위해 최소 거리 falling 구한 뒤 떨)
// Step 3. Apply gravity to those that are not connected to the ground ★
// Ground numbers : 0, 1, 2, ..., C-1
bottom = vi(C, R - 1);
int fall = INF;
vector<pii> cluster; // cluster to fall
for (int x = R - 1; x >= 0; x--) for (int y = C - 1; y >= 0; y--) {
    if (board[x][y] == '.') continue;

    // ★ [Fix] find falling range - to make whole cluster fall together
    if (g.Find(to_pos(x, y)) >= C) {
        fall = min(fall, bottom[y] - x);
        cluster.emplace_back(x, y);
    }
    else {
        bottom[y] = x - 1;
    }
}

// Execute falling
for (pii& p : cluster) {
    auto [x, y] = p;
    board[x][y] = '.';
    board[x + fall][y] = 'x';
}

 

 

 

어려운 점

1. '떨어뜨릴 클러스터를 어떻게 판별할 것인가'

→ 클러스터는 Union-Find로 구분 (그룹이 다르면 다른 클러스터).

바닥에 붙어있는 그룹들이 있는데, 이 그룹에 속하지 않은 클러스터가 있다? = 공중에 떠 있음. 떨어뜨리기

 

2. '어떻게 한꺼번에 떨어뜨릴 것인가'

→ 하나씩 떨어뜨리면 클러스터 부서짐.

클러스터 맨 아래 레이어의 원소들이 떨어질 거리 중 최소값만으로 전체 클러스터가 떨어져야 함.

 


오랜만에 Union-Find 써보는거라 Union 개념을 헷갈림.

그냥 두 집합 간에 Union 한번만 써주면, 각 집합 내에 있는 원소들 모두에 적용됨

(왜? Find는 집합의 root를 찾아주는데, Find를 이용해서 두 root를 Union 하니까)

 

BOJ 백조의 호수 풀었던 경험이 Union-Find에 익숙해지는데 도움이 됐던 것 같음!https://goldenriver42.tistory.com/39?category=943305

+ Recent posts