백준 20061번: 모노미노도미노 2 [C++]

골드 II 골드 II

문제

모노미노도미노 2

풀이

파란색 보드는 초록색 모드의 행과 열을 서로 바꿔서 생각하면 같은 보드입니다.

저는 초록색 보드를 클래스로 구현한 뒤 파란색 보드는 같은 클래스를 사용했습니다.

빨간색 칸에 블록을 놓는 것을 초록색 보드의 0행에 놓고 떨어뜨리는 것으로 생각합시다. 세로 블록은 한 칸 짜리 블록을 두 번 떨어뜨리는 것으로 생각해도 됩니다.

블록을 최대한 떨어뜨린 다음 점수를 계산하여 꽉 찬 행은 비우고 아래로 한 칸 잡아당겨 줍시다.

이는 문제 본문의 맨 마지막 부분에 의한 순서입니다.

행이나 열이 타일로 가득찬 경우와 연한 칸에 블록이 있는 경우가 동시에 발생할 수 있다. 이 경우에는 행이나 열이 타일로 가득 찬 경우가 없을 때까지 점수를 획득하는 과정이 모두 진행된 후, 연한 칸에 블록이 있는 경우를 처리해야 한다.

그럼에도 불구하고 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <bits/stdc++.h>
#ifndef ONLINE_JUDGE
#define ASSERT(x) assert(x)
#else
#define ASSERT(_) ((void)0)
#endif
using namespace std;

struct Board {
    static constexpr int h = 6, w = 4;
    int score = 0;
    bool board[h][w] = {};

    void addBlock(const vector<int>& columns) {
        vector<pair<int, int>> blocks(columns.size());
        for (int i = 0; i < blocks.size(); i++)
            blocks[i] = {0, columns[i]};

        while (true) {
            bool canMoveDown = true;

            for (auto [r, c] : blocks) {
                if (r == h - 1 or board[r + 1][c]) {
                    canMoveDown = false;
                    break;
                }
            }

            if (not canMoveDown)
                break;

            for (auto& [r, c] : blocks)
                r++;
        }

        for (auto [r, c] : blocks)
            board[r][c] = true;

        scoring();

        int minRow = h;
        for (auto [r, _] : blocks)
            minRow = min(minRow, r);

        if (minRow >= 2)
            return;

        for (int i = 0; i < 2 - minRow; i++) {
            clear(h - 1);
            pullDown(h - 2);
        }
    }

    void scoring() {
        for (int r = h - 1; r >= 0; r--) {
            while (true) {
                bool all = true;

                for (int c = 0; c < w; c++)
                    if (not board[r][c])
                        all = false;

                if (not all)
                    break;
                score++;

                clear(r);
                pullDown(r - 1);
            }
        }
    }

    void clear(int row) { fill(board[row], board[row] + w, false); }

    void pullDown(int row) {
        for (int r = row; r >= 0; r--) {
            for (int c = 0; c < w; c++)
                swap(board[r][c], board[r + 1][c]);
        }
    }

    int count() {
        int ret = 0;

        for (int r = 0; r < h; r++) {
            for (int c = 0; c < w; c++) {
                if (board[r][c])
                    ret++;
            }
        }

        return ret;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    Board green, blue;

    int N;
    cin >> N;

    while (N--) {
        int t, row, col;
        cin >> t >> row >> col;

        if (t == 1) {
            green.addBlock({col});
            blue.addBlock({row});
        } else if (t == 2) {
            green.addBlock({col, col + 1});
            blue.addBlock({row});
            blue.addBlock({row});
        } else if (t == 3) {
            green.addBlock({col});
            green.addBlock({col});
            blue.addBlock({row, row + 1});
        }
    }

    cout << green.score + blue.score << '\n' << green.count() + blue.count();

    return 0;
}

백준 20061번: 모노미노도미노 2 [C++]