[Programmers]블록 게임

1 분 소요

해결

여러가지 조건들을 유념하며 구현하면 되는 문제이며 간단한 아이디어로 구현이 깔끔해진다. 그 아이디어는 만들어 질 수 있는 크기 내에서 모든 칸을 계산하는 것이다.

직사각형 구역 안을 탐색

모든 조각은 2x3 or 3x2 직사각형에서 빈 칸을 뚫으면 만들 수 있다. 맵에 모든 곳을 이 직사각형 구역 안을 탐색하는데 위쪽 블록부터 제거하기 위해 왼쪽 위에서 부터 탐색을 한다.

이때 직사각형 구역에 빈 칸이 3개 이상이면 조각이 아니기 때문에 탐색을 그만둔다. 또한 빈 곳이 있는데 위쪽이 막혀 그 곳에 1x1조각을 떨어뜨릴 수 없을 경우와 구역 내에 다른 조각이 섞여 있다면 탐색을 그만한다.

조각이 완성되면 해당 조각을 지워준다. 더 이상 완성시킬 조각이 없다면 결과를 반환하면 된다.

구현

구현 시 탐색 할 직사각형 구역이 범위에 벗어나지 않도록 주의해야 한다.

#include <string>
#include <vector>
using namespace std;

vector<vector<int> > map;
int n;

bool canDrop(int r, int c) {
    for(int i=0;i<r;++i)
        // 막힌 부분이 존재하면 안된다.
        if(map[i][c]!=0) 
            return false;
    return true;
}

bool canFill(int row, int col, int h, int w) {
    int empty=0, id=-1;
    for(int y=row;y<row+h;++y)
        for(int x=col;x<col+w;++x) {
            // 블록이 빈 곳을 찾았다.
            if(map[y][x]==0) {
                // 빈 곳인데 떨굴 수 없다.
                if(!canDrop(y,x)) 
                    return false;
                // 빈 공간이 3칸이 넘으면 없는 블록이다.
                if(++empty>2)
                    return false;
            }
            else {
                // 블록에 다른 블록이 섞여있다.
                if(id!=-1 && id!=map[y][x])
                    return false;
                id=map[y][x];
            }
        }
    for(int y=row;y<row+h;++y)
        for(int x=col;x<col+w;++x)
            map[y][x]=0;
    return true;
}

int solution(vector<vector<int>> board) {
    map=board;
    n=map.size();
    int ret=0;
    bool can=true;
    while(can) {
        can=false;
        // 모든 맵의 3x2 or 2x3 블럭을 찾는다.
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j) {
                // 블럭이 범위를 벗어나면 안된다.
                if(i<=n-3 && j<=n-2 && canFill(i,j,3,2)) {
                    ++ret;
                    can=true;
                }
                else if(i<=n-2 && j<=n-3 && canFill(i,j,2,3)) {
                    ++ret;
                    can=true;
                }
            }
    } 
    return ret;
}

댓글남기기