[알고리즘 풀이 분석] 프로그래머스 프렌즈4블록

nnnyeong·2022년 4월 7일
0

알고리즘 풀이분석

목록 보기
98/101

오늘은 2018 카카오 1차 기출인 프로그래머스 프렌즈 4블록 을 풀어보았다!




프로그래머스 프렌즈4블록

블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 "프렌즈4블록".
같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다.

만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면 한꺼번에 지워진다.

블록이 지워진 후에 위에 있는 블록이 아래로 떨어져 빈 공간을 채우게 된다.

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.

위 초기 배치를 문자로 표시하면 아래와 같다.

TTTANT
RRFACC
RRRFCC
TRRRAA
TTMMMF
TMMTTJ

각 문자는 라이언(R), 무지(M), 어피치(A), 프로도(F), 네오(N), 튜브(T), 제이지(J), 콘(C)을 의미한다

입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.




입출력

mnboardanswer
45["CCBDE", "AAADE", "AAABF", "CCBBF"]14
66["TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"]15



나의 풀이

입력 값의 크기가 최대 900 이기 때문에 쉽게 접근해서 정확히 푸는 문제가 아닐까 생각했다.

문제를 크게 두 과정으로 나누어서 진행할 수 있는데 4개의 문자가 동일한 블록을 확인하는 과정과 블록이 사라지고 난 뒤 위에 있던 블록들이 아래로 내려오도록 조정하는 과정이다.

지워질 수 있는 블록들을 확인하는 과정에서 중복되는 블록이 없도록 하는 방법을 조금 고민했는데, 다른 블로그 글을 참고해 set 자료형을 사용할 수 있음을 참고했다. (1,1) - (m-1,n-1) 을 탐색하면서 4개의 블록이 빈칸이 아니고 모두 같은지 확인하고 해당 블록 위치를 쌍으로 묶어서 set 에 저장했다. 이후 탐색이 끝나면 set 의 크기가 지워질 수 있는 블록의 수로 반환되고 해당 값이 0보다 크면 반복해서 탐색할 수 있도록 했다.

위에 있던 블록들을 아래로 내리는 과정도 역시 고민 했지만, 그냥 무식하게 하는게 좋을 것 같았다. 1열부터 n열까지 밑에서부터 빈칸이 아닌 블록 문자만 vector 에 담아두고 이것을 다시 m 행부터 위쪽으로 빈칸없이 입력 후 남은 칸들은 모두 빈칸으로 처리 할 수 있도록 했다.

어렵지 않은 것 같은데 왜 까다롭지..? 싶었는데 기출 해설을 보니 난이도가 상으로 표시되어 있어서 의외면서도 약간 끄덕여졌다. 고민 없이 바로 정확하게 풀 수 있는 능력을 보는 문제였던 것 같다.




코드

#include <string>
#include <vector>
#include <set>

// 프로그래머스 프렌즈4블록, level2
using namespace std;

vector<vector<char>> matrix;

int countRemovable(int m, int n){
    set<pair<int, int>> check;
    vector<vector<char>> removed = matrix;

    for (int i = 1; i <= m-1; ++i) {
        for (int j = 1; j <= n-1; ++j) {
            if ( matrix[i][j]!='-' && matrix[i][j] == matrix[i][j+1]  && matrix[i][j] == matrix[i+1][j] && matrix[i][j] == matrix[i+1][j+1]) {
                removed[i][j] = '-';
                if (check.find({i, j}) == check.end()) check.insert({i, j});
                removed[i][j + 1] = '-';
                if (check.find({i, j + 1}) == check.end()) check.insert({i, j + 1});
                removed[i + 1][j] = '-';
                if (check.find({i + 1, j}) == check.end()) check.insert({i + 1, j});
                removed[i + 1][j + 1] = '-';
                if (check.find({i + 1, j + 1}) == check.end()) check.insert({i + 1, j + 1});
            }
        }
    }
    matrix = removed;

    return check.size();
}

void arrangeBlock(int m, int n){

    for (int j = 1; j <= n; ++j) {
        vector<char> col;
        for (int i = m; i >= 1; --i) {
            if (matrix[i][j] != '-') col.push_back(matrix[i][j]);
        }

        for (int i = 0; i < col.size(); ++i) {
            matrix[m-i][j] = col[i];
        }

        if (col.size() == m) continue;
        for (int i = m-col.size(); i >= 1; --i) matrix[i][j] = '-';
    }
}

int solution(int m, int n, vector<string> board) {
    int answer = 0;

    matrix.assign(m+1, vector<char>(n+1, ' '));
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) matrix[i][j] = board[i-1][j-1];
    }

    int removable = countRemovable(m,n);
    answer += removable;
    while (removable > 0){
        arrangeBlock(m,n);
        removable = countRemovable(m,n);
        answer += removable;
    }

    return answer;
}
profile
주니어 개발자까지 ☄️☄️

0개의 댓글