경주장

[BOJ]9207_페그 솔리테어 본문

코테/백준

[BOJ]9207_페그 솔리테어

달리는치타 2021. 12. 25. 00:00

문제를 이해하는데 조금 어려웠습니다.

 

게임판에 핀이 나란히 있고 다음칸이 비어있다면 두 핀은 모두 사라지고 다음칸에 핀이 생깁니다.

첫번째 TC : 

###...###
..oo.....
.....oo..
.........
###...###
moveCnt 0 , pinCnt 4
=>

###...###
....o....
.....oo..
.........
###...###
moveCnt 1 , pinCnt 3
=>

###...###
....o....
....o....
.........
###...###
moveCnt 2 , pinCnt 2
=>

###...###
.........
....o....
.........
###...###
moveCnt 3 , pinCnt 1

게임의 규칙과 위의 TC에서 알 수 있듯이 한번 이동할때 마다 pin은 하나씩 사라집니다.

 

 

최소움직임의 경우를 구하는 문제인 만큼 BFS를 떠올렸고 게임의 전체 정보를 저장할 info 구조체를 만들었습니다.

typedef vector<vector<char>> vvc;

typedef struct _info{
    vvc board;			
    int pinCnt;
    int moveCnt;
}info;

게임의 정보를 저장할때 핀의 위치정보만 비트마스킹과 같은 방식을 통해 저장하는 방식을 고민해 보았지만 잘 떠오르지 않았습니다.

 

다른 분들의 풀이를 보고 다시 생각해보니 이 문제는 핀의 최소 개수와 그 개수를 만들기 위해 필요한 최소 이동 횟수를 구하는 문제이므로 사실상 가능한 움직임 중 최대 이동 횟수를 구하는 문제입니다.  

 

따라서 BFS와 DFS (백트래킹) 모두 시간 복잡도 측면에서는 동일하지만 queue를 활용하는 BFS가 공간적으로 더 좋지 않습니다. 하지만 visited를 저장하여 중복되는 가지를 자르는 아이디어는 BFS,DFS모두 동일하게 적용이 가능합니다.

#include <iostream>
#include <queue>
#include <vector>
#include <set>

#define ROW 5
#define COL 9

using namespace std;

typedef vector<vector<char>> vvc;
vvc board;
set<vvc> visited;

int TC;
int pinCnt;

void input(){
    for(int r= 0 ; r < ROW ; r++){
        for(int c= 0 ;  c<COL ;c++){
            cin>>board[r][c];
            if(board[r][c]=='o') pinCnt++;
        }
    }
}

typedef struct _info{
    vvc board;
    int pinCnt;
    int moveCnt;
}info;

//D,U,R,L
int dy[4] = {1,-1,0,0};
int dx[4] = {0,0,1,-1};

bool isValid(int r, int c){
    return r>=0 && r<ROW && c>=0 && c<COL;
}

vvc moveBoard(vvc board, int r, int c, int d){
    int tr1 = r+dy[d];
    int tc1 = c+dx[d];
    int tr2 = r+2*dy[d];
    int tc2 = c+2*dx[d];

    board[r][c] = '.';
    board[tr1][tc1] = '.';
    board[tr2][tc2] = 'o';

    return board;
}

void solve(){
    info init;
    visited.insert(board);

    init.board = board;
    init.pinCnt = pinCnt;
    init.moveCnt = 0;

    queue<info> q;
    q.push(init);

    int minPinCnt;
    int minMoveCnt;

    while(!q.empty()){
        info pos = q.front();
        q.pop();
        vvc cur = pos.board;
        minPinCnt = pos.pinCnt;
        minMoveCnt = pos.moveCnt;

        for(int r= 0 ;r < ROW; r++){
            for(int c= 0 ;c < COL ; c++){
                if(cur[r][c]=='o'){
                    for(int d= 0; d< 4 ;d ++){
                        int tr1 = r+dy[d];
                        int tc1 = c+dx[d];
                        int tr2 = r+2*dy[d];
                        int tc2 = c+2*dx[d];

                        if(isValid(tr2,tc2)  && cur[tr2][tc2]=='.'&& cur[tr1][tc1] =='o'){
                            vvc moved = moveBoard(cur,r,c,d);
                            if(visited.find(moved)==visited.end()){
                                visited.insert(moved);
                                q.push({moved,pos.pinCnt-1,pos.moveCnt+1});
                            }
                        }
                    }
                }
            }
        }
    }

    printf("%d %d\n", minPinCnt, minMoveCnt);
}

void clear(){
    visited.clear();
    pinCnt = 0;
}

int main(){
    cin>>TC;
    board = vector<vector<char>>(ROW, vector<char>(COL,'.'));

    for(int i = 0 ; i < TC ; i++){
        input();
        solve();
        clear();
    }
}

 

'코테 > 백준' 카테고리의 다른 글

[BOJ]16637_괄호 추가하기  (0) 2021.07.03
[BOJ]2671_잠수함식별  (0) 2021.03.09