모노미노도미노 19235

PublicMinsu·2023년 9월 9일
0

문제


생략

접근 방법

구현 문제이다.
각각에 해당하는 부분은 함수로 나누어서 작성해 주는 게 좋다.

초록색 보드를 돌려놓으면 파란색 보드가 되는 것을 알 수 있다. 그렇기에 파란색 보드에는 돌려놓은 값을 대입하면 된다.

한 줄이 가득 차 있는 경우를 확인할 때 위에서부터 확인해 준 뒤 (왜냐하면 블록은 위에서부터 내려오니까) 가득 찬 경우에는 지워주고 해당 줄 위에서부터 내려오게 해주면 된다.

연한 칸에 값이 존재할 때는 밑을 지우고 위에 있는 값들을 내려오게 하면 된다.

각각의 블록은 줄이 사라지면서 분리되지 않는 한 같이 내려와야 한다. 또한 같은 타입이어도 따로 생성된 것이라면 다른 블록이기에 구분해 주는 값을 대입해 줘야 한다.

같은 타입+같은 블록을 묶어서 내려오게 해주는 것이 중요한 것이다.
도중에 줄이 삭제되면서 1칸으로 되는 경우가 존재한다. 그런 경우에는 타입을 변경하면 된다.

코드

#include <iostream>
using namespace std;
int map[2][6][4]; // false은 초록, true은 파랑
int ret;
// 타입 확인 (끊기는 경우도 있음 그럴 경우 1로 반환)
int checkType(bool isBlue, int x, int y)
{
    if (y + 1 < 4 && map[isBlue][x][y] == map[isBlue][x][y + 1])
        return 2;
    else if (x - 1 >= 0 && map[isBlue][x][y] == map[isBlue][x - 1][y])
        return 3;
    else
        return 1;
}
// 블록 설치해주기
void setBlock(bool isBlue, int x, int y, int t, int idx)
{
    map[isBlue][x][y] = idx;
    if (t == 2)
        map[isBlue][x][y + 1] = idx;
    else if (t == 3)
        map[isBlue][x - 1][y] = idx;
}
// 밑으로 내려가기
void drop(bool isBlue, int x, int y, int t, int idx)
{
    for (int i = x; i < 6; ++i)
    {
        if (map[isBlue][i][y]) // 해당 위치에 블럭이 있다면 이전 높이에 설치
        {
            setBlock(isBlue, i - 1, y, t, idx);
            return;
        }
        else if (t == 2 && map[isBlue][i][y + 1]) // 가로가 긴 경우
        {
            setBlock(isBlue, i - 1, y, t, idx);
            return;
        }
    }
    setBlock(isBlue, 5, y, t, idx);
}
// 삭제 후 위의 블럭들 타입 유지하여 밑으로 내리기
void remove(bool isBlue, int x)
{
    for (int i = 0; i < 4; ++i)
        map[isBlue][x][i] = 0;
    for (int i = x - 1; i >= 0; --i)
    {
        for (int j = 0; j < 4; ++j)
        {
            if (!map[isBlue][i][j])
                continue;
            int idx = map[isBlue][i][j];
            int type = checkType(isBlue, i, j);
            map[isBlue][i][j] = 0;
            if (type == 2)
                map[isBlue][i][j + 1] = 0;
            else if (type == 3)
                map[isBlue][i - 1][j] = 0;
            drop(isBlue, i, j, type, idx);
        }
    }
}
// 한 줄이 가득찬지 확인
void checkFull(bool isBlue)
{
    for (int i = 0; i < 6; ++i)
    {
        int cnt = 0;
        for (int j = 0; j < 4; ++j)
            if (map[isBlue][i][j])
                ++cnt;
        if (cnt == 4)
        {
            ++ret;
            remove(isBlue, i);
        }
    }
}
// 확인 후 가장 밑에 값 삭제
void checkLimit(bool isBlue)
{
    for (int i = 0; i <= 1; ++i)
        for (int j = 0; j < 4; ++j)
            if (map[isBlue][i][j])
                remove(isBlue, 5);
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    int N, t, x, y, idx = 0, cnt = 0;
    cin >> N;
    while (N--)
    {
        cin >> t >> x >> y;
        drop(false, 0, y, t, ++idx);
        if (t == 1)
            drop(true, 0, x, 1, idx);
        else if (t == 2)
            drop(true, 0, x, 3, idx);
        else
            drop(true, 0, x, 2, idx);
        checkFull(false);
        checkFull(true);
        checkLimit(false);
        checkLimit(true);
    }
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 6; ++j)
            for (int k = 0; k < 4; ++k)
                if (map[i][j][k])
                    ++cnt;
    cout << ret << "\n"
         << cnt;
    return 0;
}

풀이

어떤 식으로 접근해야 할 진 알겠는데 그대로 구현하면 너무 하드코딩일 것 같아서 다른 사람의 풀이를 참고했다.

처음엔 지도에 타입을 기재해도 될 거로 생각했다. 하지만 타입의 경우 다른 블록과 구분이 안 된다는 점에서 문제가 발생할 수 있다. 그렇기에 고유한 식별 값을 넣어주는 것이 중요하다.

profile
연락 : publicminsu@naver.com

0개의 댓글