[백준] 19235 모노미노도미노 (C++)

Yookyubin·2023년 9월 8일
0

백준

목록 보기
56/68

문제

19235번: 모노미노도미노

풀이

별다른 알고리즘 없이 그냥 구현 문제였다.

파란색보드와 초록색보드가 서로대칭이다 보니 6X4 모양의 보드 하나로 퉁치고 계산했다.
파란색보드에 입력할 때 빨간보드의x,y 좌표를 서로 바꾸어 주면 된다.

두 보드 모두 6X4로 사용하기 때문에 두개를 붙인 블럭은 가로방향일 때만 신경써주면 된다.
물론 입력을 받을 때 t=2 혹은 t=3 인경우에 대칭이동을 시켜주어야 한다.
블럭이 세로인경우는 t=1 이 2번 호출된다고 간주하고 입력을 받았다.
가로 블럭의 경우 입력으로 주어진 x,y와 그에 종속적으로 x,y+1까지 고려해야 한다.
y 와 y+1 중 높이가 더 높은 위치에 해당하도록 한다.
계산은 항상 x,y에서만 진행하도록 x,y+1의 블럭은 type=3으로 하여 자체적으로 높이 계산을 못하도록 했다. 항상 x,y 위치에서만 연산하고 그 결과에 따라다니도록 했다. x,y에서 y+1의 위치까지도 고려해주므로 계산 결과는 문제가 없다.

코드

#include <iostream>
#include <vector>

using namespace std;

int min(int a, int b) { return a < b ? a : b; }

// 블럭들 가라앉히기
void setBlock(int type, int x, int y, vector<vector<int>>& board)
{
    int newX = 5;
    board[x][y] = 0;

    for (int i=x+1; i<6; ++i)
    {
        if (board[i][y] == 0)
            continue;
        
        newX = i-1;
        break;
    }

    if (type == 2)
    {
        board[x][y+1] = 0;
        for (int i=x+1; i<6; ++i) // i의 시작 지점이 입력으로 받을 때와 블록이 사라져서 내려갈때가 다르다. 이건 입력부분에서 0으로 맞춰주면 될듯?
        {
            if (board[i][y+1] == 0)
                continue;
            
            newX = min(newX, i-1);
            break;
        }
    }

    board[newX][y] = type;
    if (type == 2)
        board[newX][y+1] = 3;
}

// 채워진 줄 찾고 삭제시키기
int checkRow(vector<vector<int>>& board)
{
    int cnt = 0;
    for (int row=0; row<6; ++row)
    {
        int cntZero = 0;
        for (int i=0; i<4; ++i)
        {   
            if (board[row][i] == 0)
                ++cntZero;

        }

        if (cntZero > 0)
            continue;

        for (int i=0; i<4; ++i)
            board[row][i] = 0;

        cnt += 1;
    }

    return cnt;
}

int main ()
{
    cin.tie(0);
    ios_base::sync_with_stdio(false);

    int score = 0;
    vector<vector<int>> blue = vector<vector<int>>(6, vector<int>(4));
    vector<vector<int>> green = vector<vector<int>>(6, vector<int>(4));

    int n; cin >> n;

    while (n--)
    {
        int t, x, y;
        cin >> t >> x >> y;
        switch(t)
        {
            case(1):
                setBlock(1, 0, y, green);
                setBlock(1, 0, x, blue);
                break;
            case(2):
                setBlock(2, 0, y, green);
                setBlock(1, 0, x, blue); // 혹시 몰라서 아래에 있는 블록 먼저 떨구기
                setBlock(1, 0, x, blue);
                break;
            case(3):
                setBlock(1, 0, y, green);
                setBlock(1, 0, y, green);
                setBlock(2, 0, x, blue);
                break;
        }
        
        // 줄 채운거 삭제 시키고 밑으로 내리기
        while (true)
        {
            int temp = checkRow(green);
            if (temp == 0)
                break;
            
            score += temp;
            for (int i=5; i>= 0; --i) // 아랫줄부터 처리해야 한다.
                for (int j=0; j<4; ++j)
                    if (green[i][j] == 1 || green[i][j] == 2)
                        setBlock(green[i][j], i, j, green);
        }

        while (true)
        {
            int temp = checkRow(blue);
            if (temp == 0)
                break;

            score += temp;
            for (int i=5; i>=0; --i)
                for (int j=0; j<4; ++j)
                    if (blue[i][j] == 1 || blue[i][j] == 2)
                        setBlock(blue[i][j], i, j, blue);
        }

        // 0, 1 초과분 밀어넣기
        for (int qq = 0; qq < 2; ++qq)
            for (int i=0; i<4; ++i)
            {
                if (green[1][i] != 0)
                {
                    for (int r=5; r>=1; --r)
                    {
                        for (int c=0; c<4; ++c)
                        {
                            green[r][c] = green[r-1][c];
                        }
                    }
                    for (int c=0; c<4; ++c)
                        green[0][c] = 0;
                    break;
                }
            }

        for (int qq = 0; qq < 2; ++qq)
            for (int i=0; i<4; ++i)
            {
                if (blue[1][i] != 0)
                {
                    for (int r=5; r>=1; --r)
                    {
                        for (int c=0; c<4; ++c)
                        {
                            blue[r][c] = blue[r-1][c];
                        }
                    }
                    for (int c=0; c<4; ++c)
                        blue[0][c] = 0;
                    break;
                }
            }

    }
    
    // 남아있는거 계산
    int left = 0;
    for (int i=0; i<6; ++i)
    {
        for (int j=0; j<6; ++j)
        {
            if (green[i][j] != 0)
                ++left;
            if (blue[i][j] != 0)
                ++left;
        }
    }

    cout << score << endl;
    cout << left << endl;
    return 0;
}
profile
붉은다리 제프

0개의 댓글