본문 바로가기

BOJ/이건 '진짜'다

백준 9376 / 탈옥



이 문제를 단번에 풀었다면 나는 당장 하산했을 것이다.



처음 문제를 풀었을 때 여러가지 해결법이 떠올랐다.


그중 가장 그럴 듯 했던건 모든 문의 좌표를 받고 


0개를 열었을 때, 1개를 열었을 때, 2개를 열었을 때 ...... n개를 열었을 때


탈옥에 성공하는 문의 최소개수를 구하는 방법이었는데. 


한 케이스당 bfs를 2번씩 해야되니 시간초과에 걸렸다. 맵이 작았으면 괜찮았을 텐데..






이 문제의 해결법은 이렇다.


죄수1과 죄수2 그리고 맵 밖에 있는 사람이 있다고 가정하자. (문제에 힌트가 있다. 상근이는 어디에나 있을 수 있다고..)


맵도 바꿔준다.


맵의 가장자리 부분에 빈공간(.)를 추가시켜준다.



그리고 죄수1과 죄수2 밖의사람의 모든 dist를 bfs로 구한다


이떄 문이 아닌 빈 공간을 지나가는 경우는 가중치가 0이고 문을 지나가는 것은 가중치가 1이다. 


이 점 때문에 시간을 줄이기 위해 queue 대신 deque를 써야한다.


그냥 빈공간을 지나가는 경우 push_front, 문을 지나가는 경우 push_back.



죄수1과 죄수2 밖의사람의 dist를 모두 구했다면 전부 더해준다.


이떄, 벽이라면 그냥 continue (벽을 지나가는건 말이 안되기 떄문에)


문이라면 더한 값에 -2를 해주어야한다. (문 하나를 세번 연 것으로 치기때문에 한 번만 연 것으로 표시하기 위해)



이렇게 더한 dist에서 최소값을 출력하면 답이다.






이 아이디어는 


죄수1이 죄수2과 (x,y)에서 만나서 밖으로 나가는 로직에서 한 단계 발전시킨 것이다.


죄수1와 죄수2가 만나서 밖에 나가는 로직은 bfs를 총 n x m 만큼 해야되기 떄문에 비효율적.


그리하여 밖에 있는 사람도 감옥안에 들어오면서 죄수1과 죄수2를 만나는 로직을 세운 것이다.




진짜,


이 문제를 단번에 풀었다면 나는 당장 하산했을 것이다.






코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<stdio.h>
#include<iostream>
#include<vector>
#include<queue>
#include<tuple>
#include<memory.h>
 
using namespace std;
 
bool check[105][105];
 
 
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,1,-1 };
 
int h, w;
 
deque<pair<intint>>dq;
 
vector<vector<int>>go(vector<vector<char>>map, int x, int y) {
 
    vector<vector<int>>dist(h + 2vector<int>(w + 20));
 
    memset(check, falsesizeof(check));
    dist[x][y] = 0;    
    dq.push_front({ x,y });
 
    while (!dq.empty()) {
        int x = dq.front().first;
        int y = dq.front().second;
        dq.pop_front();
 
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
 
            if (nx >= 0 && ny >= 0 && nx < h + 2 && ny < w + 2) {
                if (check[nx][ny] == false) {
                    if (map[nx][ny] == '.' || map[nx][ny] == '$') {
                        check[nx][ny] = true;
                        dist[nx][ny] = dist[x][y];
                        dq.push_front({ nx,ny });
                    }
                    if (map[nx][ny] == '#') {
                        check[nx][ny] = true;
                        dist[nx][ny] = dist[x][y] + 1;
                        dq.push_back({ nx,ny });
                    }
                }
            }
        }
    }
 
    return dist;
}
int main() {
    
    //freopen("Text.txt", "r", stdin);
 
    int testcase;
    cin >> testcase;
    
    while (testcase--) {
 
 
        vector<vector<char>>map(105vector<char>(105));
        vector<pair<intint>>pri;
 
        cin >> h >> w;
        
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                cin >> map[i+1][j+1];
            }
        }
 
        bool first = false;
 
        for (int i = 0; i < h + 2; i++) {
            for (int j = 0; j < w + 2; j++) {
                if (map[i][j] == NULL) {
                    map[i][j] = '.';
                }
                if (map[i][j] == '$') {
                    pri.push_back({ i,j });
                }
            }
        }
 
        vector<vector<int>>dist00 = go(map,00);
        vector<vector<int>>dist1 = go(map,pri[0].first, pri[0].second);
        vector<vector<int>>dist2 = go(map, pri[1].first, pri[1].second);
 
        int min = h*w;
 
        for (int i = 0; i < h + 2; i++) {
            for (int j = 0; j < w + 2; j++) {
                if (map[i][j] == '*') {
                    continue;
                }
                int a = dist00[i][j];
                int b = dist1[i][j];
                int c = dist2[i][j];
 
                int cur = a + b + c;
        
                if (map[i][j] == '#') {
                    cur = cur - 2;
                }
                if (min > cur) {
                    min = cur;
                }
            }    
        }
        cout << min << endl;
 
    }
}
cs


'BOJ > 이건 '진짜'다' 카테고리의 다른 글

백준 13460 / 구슬 탈출 2 (해결)  (0) 2019.01.26