Algorithm

[Algorithm] 백준 13460번 : 구슬 탈출 2

dokylee 2020. 9. 10. 21:36

 

https://www.acmicpc.net/problem/13460

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

 

카카오 코테 풀다가 죽을 것 같아서 

삼성 코테 기출을 풀어보는데

 

^^... 삼성도 어려운데? 누가 쉽다고...... 내가 못하는건가....

 

 

* 이번 삽질

- 빨간공 움직이고 파란공 움직인 다음, 진짜 빨간공이 못움직였던게 맞는지 한번더 빨간공 확인하는 작업

- 답 리턴할 때는 continue 조건 다 지난 이후에 return

- 중복 방문이 허용되는지 잘 파악하고 check 방문 배열을 쓰자.. 이번껀 중복 되는건데 방문 했으면 못가게 해서 막힘.. 중간에 check 보긴 했는데 아 맞겟지머~~ 하고 넘어간거에.. 몇십분을 날린건지..

 

 

Code

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

struct pos
{
    int redx, redy, bluex, bluey, dist, redsuccess, bluesuccess;
};

int main() {

    int n, m;
    int vv[10][10] = {0, }, check[10][10] = {0, };
    int mv[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    int redx, redy, bluex, bluey, holex, holey;
    
    cin >> n >> m;

    // v -> 0: 길, 1:막힘, 2: 빨간공, 3: 파란공, 4: 구멍
    for(int i=0; i<n; i++) {
        string tmp;
        cin >> tmp;
        for(int j=0; j<m; j++) {
            unsigned char c = tmp[j];
            if(c==(unsigned char)'.') vv[i][j] = 0;
            if(c==(unsigned char)'#') {
                vv[i][j] = 1;
            }
            if(c==(unsigned char)'R') {
                vv[i][j] = 0;
                redx = i;
                redy = j;
            }
            if(c==(unsigned char)'B') {
                vv[i][j] = 0;
                bluex = i;
                bluey = j;
            }
            if(c==(unsigned char)'O') {
                vv[i][j] = 4;
                holex = i;
                holey = j;
            }
        }
    }

    queue<pos> q;
    
    q.push({redx, redy, bluex, bluey, 0, 0, 0});

    while(!q.empty()) {
        int redx = q.front().redx, redy = q.front().redy;
        int bluex = q.front().bluex, bluey = q.front().bluey;
        int dist = q.front().dist;
        int rsuc = q.front().redsuccess, bsuc = q.front().bluesuccess;

        q.pop();

        // 파란공이 빠졌거나 이동이 10번이 넘어갔으면 이번 푸시된 큐는 무시
        if(bsuc==1 || dist == 11) continue;

        if(rsuc == 1 && bsuc == 0){
            cout << dist;
            return 0;
        }

        for(int i=0; i<4; i++) {
            int dx = mv[i][0], dy = mv[i][1];
            int rednx, redny, bluenx, blueny;
            int ndist = dist + 1;
            int redsuccess = 0, bluesuccess = 0, redstop = 0, bluestop = 0;
            int idx = 0;
            int flag = 0;

            // 계속 돌려줄 현재 보드 상태 v (이동마다 이어지지 않고 새롭게 배치할 수 있도록)
            int v[10][10] = {0, };
            memcpy(v, vv, sizeof(vv)); // 맨 처음 vv에 넣어둔 미로를 복사함

            // 복사한 곳에 현재 빨간공과 파란공 배치
            v[redx][redy] = 2;
            v[bluex][bluey] = 3;

            // 기울이기
            while(1) {

                // 빨간공 파란공 다 멈췄으면 그만 기울이기
                if(redstop && bluestop) break;

                // 빨간공 안멈췄고 성공도 못했으면 다시 움직임 (기울이기니까)
                if(!redsuccess && !redstop) {
                    // 빨간공 이동
                    if(idx == 0) {
                        rednx = redx + dx;
                        redny = redy + dy;                      
                    }
                    else {
                        rednx += dx;
                        redny += dy;
                    }

                    // 공이 지나갔으니까 길 됨
                    v[rednx-dx][redny-dy] = 0;
                    
                    /* 빨간색 공 조건 */
                    // 벽이거나 파란공이면 멈춤
                    if(v[rednx][redny]==1 || v[rednx][redny]==3) {
                        rednx -= dx;
                        redny -= dy;
                        flag = 1;
                    }

                    // 이동한 자리는 빨간공
                    v[rednx][redny] = 2;


                    // 구멍 만나면 성공 & 구멍 자리는 다시 4로 돌려놓기
                    if(rednx == holex && redny == holey) {
                        redsuccess = 1;
                        redstop = 1;
                        v[rednx][redny] = 4;                        
                    }
                }

                if(!bluesuccess && !bluestop) {
                    // 파란공 이동
                    if(idx == 0) {
                        bluenx = bluex + dx;
                        blueny = bluey + dy;
                    }
                    else {
                        bluenx += dx;
                        blueny += dy;
                    }

                    // 공이 지나갔으니까 길 됨
                    v[bluenx-dx][blueny-dy] = 0;

                    /* 파란색 공 조건 */
                    // 벽이거나 빨간공이면 멈춤
                    if(v[bluenx][blueny]==1 || v[bluenx][blueny]==2) {
                        bluenx -= dx;
                        blueny -= dy;
                        bluestop = 1;
                    }

                    // 이동한 자리는 파란공
                    v[bluenx][blueny] = 3;

                    // 구멍 만나면 성공+1
                    if(bluenx == holex && blueny == holey) {
                        bluesuccess = 1;
                        bluestop = 1;
                        v[bluenx][blueny] = 4;
                    }
                }

                /* 
                지금 위에 순서가 빨간공 움직일 수 있는지 조건 확인하고 파란공 조건 확인후 움직이는데, 
                파란공 움직인 후 정말 빨간공이 움직일 수 없던게 맞는지 한번더 움직여본다 
                ex) RB <- 이렇게 배치되어있고 오른쪽으로 이동하는 경우
                */
                if(flag) {
                    // 빨간공 이동
                    if(idx == 0) {
                        rednx = redx + dx;
                        redny = redy + dy;                      
                    }
                    else {
                        rednx += dx;
                        redny += dy;
                    }

                    // 공이 지나갔으니까 길 됨
                    v[rednx-dx][redny-dy] = 0;
                    
                    /* 빨간색 공 조건 */
                    // 벽이거나 파란공이면 멈춤
                    if(v[rednx][redny]==1 || v[rednx][redny]==3) {
                        rednx -= dx;
                        redny -= dy;
                        redstop = 1;
                    }
                    // 구멍 만나면 성공+1
                    if(rednx == holex && redny == holey) {
                        redsuccess = 1;
                        redstop = 1;
                    }

                    // 이동한 자리는 빨간공
                    v[rednx][redny] = 2;
                }
            
                idx++;
            }
    
            q.push({rednx, redny, bluenx, blueny, ndist, redsuccess, bluesuccess});
        }
    }

    cout << -1;
    return 0;
}