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

 

16985번: Maaaaaaaaaze

첫째 줄부터 25줄에 걸쳐 판이 주어진다. 각 판은 5줄에 걸쳐 주어지며 각 줄에는 5개의 숫자가 빈칸을 사이에 두고 주어진다. 0은 참가자가 들어갈 수 없는 칸, 1은 참가자가 들어갈 수 있는 칸을

www.acmicpc.net

오랜만에 포스팅입니다. (너무 게을러서..)

 

bfs에 브루트포스까지 섞여있는 풀이가 복잡한 문제입니다.

5x5 크기의 2차원 배열이 5개 있으니 3차원 배열이 됩니다.

(0, 0, 0)에서 출발하여 (4, 4, 4)에 도착하는 최소 이동 횟수를 요구합니다.

여기까지만 보면, 단순 bfs로도 해결이 가능합니다.

 

하지만 5x5 크기의 판들의 순서도 변경이 가능하고, 판을 회전할 수도 있습니다.

브루트포스를 이 제약조건 두 개에 각각 적용해야 합니다.

 

저는 이 판들의 인덱스로 번호를 매겼고, dfs로 순회하면서 이동 횟수의 최솟값을 구하고, 회전 로직을 구현했습니다.

1
2
3
4
do {
    copyArray();
    dfs(0);
while (next_permutation(order, order + MAX));
cs

먼저, 순열을 이용하여 판들의 순서를 바꿔줍니다.

cpp은 next_permutation을 제공하여 편하게 구현할 수 있습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void dfs(int idx) {
    if (idx == MAX) return;
 
    for (int i = 0; i < 4; i++) {
        int ret = bfs();
 
        if (ret != -1) {
            ans = min(ans, ret);
        }
 
        dfs(idx + 1);
        rotate(idx);
    }
}
cs

처음 제출했을 때의 dfs 함수입니다.

모든 경우에서 bfs로 이동 횟수를 구하고, 회전하는 방식입니다.

 

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
int bfs() {
    queue<pair<intpair<intint> > > q;
    q.push({ 0,{0,0} });
    memset(visit, falsesizeof(visit));
    visit[0][0][0= true;
    for (int t = 0!q.empty(); t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().first;
            int y = q.front().second.first;
            int z = q.front().second.second;
            q.pop();
 
            if (x == MAX - 1 && y == MAX - 1 && z == MAX - 1) {
                return t;
            }
 
            for (int d = 0; d < 6; d++) {
                int nx = x + direct[d][0];
                int ny = y + direct[d][1];
                int nz = z + direct[d][2];
 
                if (nx < 0 || ny < 0 || nz < 0 || nx >= MAX || ny >= MAX || nz >= MAX) continue;
                if (visit[nx][ny][nz] || !map[nx][ny][nz]) continue;
 
                q.push({ nx,{ny,nz} });
                visit[nx][ny][nz] = true;
            }
        }
    }
 
    return -1;
}
cs

bfs로 이동 횟수를 구합니다.

중간에 도착 지점을 만났다면 t를 리턴, 아니면 -1을 리턴합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void rotate(int idx) {
    int tmp[MAX][MAX][MAX] = { 0, };
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            tmp[idx][i][j] = map[idx][j][MAX - 1 - i];
        }
    }
 
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            map[idx][i][j] = tmp[idx][i][j];
        }
    }
}
cs

현재 단계에서 이동횟수를 모두 구했다면 배열을 회전합니다.

회전은 90도, -90도 중에 아무렇게나 해주시면 됩니다. 한 방향으로 회전하는 것이 중요합니다.

이렇게 하시면 AC는 받을 수 있습니다.

하지만 다른 분들의 실행 시간을 보니 제 코드가 비효율적으로 동작한다는 것을 깨달았고, 가지치기를 진행하였습니다.

위의 코드들은 가지치기 이전 단계의 코드이며, 변화가 있는 로직은 rotate와 dfs입니다.

 

생각을 해보니, 문제에 답이 있었다는 것을 깨달았습니다.

  1. 참가자가 들어갈 수 없는 칸이 존재한다.
    • 그 칸이 시작/도착 지점이라면 bfs 탐색할 필요가 없다.
    • 배열은 회전하므로 시작/도착 지점이 갈 수 없는 칸일 가능성이 있다.
  2. 배열 크기는 5 x 5 x 5로 고정되어 있다.
    • 탈출이 가능한 배열에서 나올 수 있는 최소 이동 횟수는 12다.
  3. 회전을 해도 이전과 같은 모양이 나올 수 있다.
    • 이미 구한 것으로 간주하고, 다음 단계를 진행할 필요가 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bool rotate(int idx) {
    int tmp[MAX][MAX][MAX] = { 0, };
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            tmp[idx][i][j] = map[idx][j][MAX - 1 - i];
        }
    }
 
    int cnt = 0;
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            if (map[idx][i][j] == tmp[idx][i][j]) cnt++;
            map[idx][i][j] = tmp[idx][i][j];
        }
    }
 
    if (cnt == MAX * MAX) return false;
    else return true;
}
cs

우선 rotate입니다.

자료형은 bool로 변경되었고, 회전한 배열이 이전 배열과 같은지 확인하는 로직만 추가되었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void dfs(int idx) {
    if (idx == MAX) {
        if (!map[MAX - 1][MAX - 1][MAX - 1]) {
            return;
        }
 
        int ret = bfs();
        if (ret != -1) {
            ans = min(ans, ret);
        }
 
        return;
    }
 
    for (int i = 0; i < 4; i++) {
        if (map[0][0][0]) {
            dfs(idx + 1);
            if (ans == MIN_ANS) return;
        }
 
        if (!rotate(idx)) return;
    }
}
cs

dfs 함수에 많은 변화가 있었습니다.

bfs 함수 호출은 모든 회전이 한 번씩 끝났을 때 진행하는 것으로 변경하였고, 출발/도착 지점에 대한것과 최솟값, rotate에 대한 가지치기가 모두 포함되어 있습니다.

이제 제출을 해보니 시간이 많이 줄어든 것을 확인할 수 있습니다.

 

 

최종 코드는 아래입니다.

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define MAX 5
#define MIN_ANS 12
using namespace std;
 
int list[MAX][MAX][MAX], map[MAX][MAX][MAX];
int order[MAX], ans;
int direct[6][3= { {0,0,1}, {0,0,-1}, {0,1,0}, {0,-1,0}, {1,0,0}, {-1,0,0} };
bool visit[MAX][MAX][MAX];
 
int bfs() {
    queue<pair<intpair<intint> > > q;
    q.push({ 0,{0,0} });
    memset(visit, falsesizeof(visit));
    visit[0][0][0= true;
    for (int t = 0!q.empty(); t++) {
        if (ans <= t) return t;
 
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().first;
            int y = q.front().second.first;
            int z = q.front().second.second;
            q.pop();
 
            if (x == MAX - 1 && y == MAX - 1 && z == MAX - 1) {
                return t;
            }
 
            for (int d = 0; d < 6; d++) {
                int nx = x + direct[d][0];
                int ny = y + direct[d][1];
                int nz = z + direct[d][2];
 
                if (nx < 0 || ny < 0 || nz < 0 || nx >= MAX || ny >= MAX || nz >= MAX) continue;
                if (visit[nx][ny][nz] || !map[nx][ny][nz]) continue;
 
                q.push({ nx,{ny,nz} });
                visit[nx][ny][nz] = true;
            }
        }
    }
 
    return -1;
}
 
bool rotate(int idx) {
    int tmp[MAX][MAX][MAX] = { 0, };
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            tmp[idx][i][j] = map[idx][j][MAX - 1 - i];
        }
    }
 
    int cnt = 0;
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            if (map[idx][i][j] == tmp[idx][i][j]) cnt++;
            map[idx][i][j] = tmp[idx][i][j];
        }
    }
 
    if (cnt == MAX * MAX) return false;
    else return true;
}
 
void dfs(int idx) {
    if (idx == MAX) {
        if (!map[MAX - 1][MAX - 1][MAX - 1]) {
            return;
        }
 
        int ret = bfs();
        if (ret != -1) {
            ans = min(ans, ret);
        }
 
        return;
    }
 
    for (int i = 0; i < 4; i++) {
        if (map[0][0][0]) {
            dfs(idx + 1);
            if (ans == MIN_ANS) return;
        }
 
        if (!rotate(idx)) return;
    }
}
 
void copyArray() {
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            for (int k = 0; k < MAX; k++) {
                map[order[i]][j][k] = list[i][j][k];
            }
        }
    }
}
 
void func() {
    ans = 1e9;
    do {
        copyArray();
        dfs(0);
    } while (next_permutation(order, order + MAX));
 
    if (ans == 1e9) ans = -1;
    cout << ans << '\n';
}
 
void input() {
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            for (int k = 0; k < MAX; k++) {
                cin >> list[i][j][k];
            }
        }
        order[i] = i;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 14466 소가 길을 건너간 이유 6  (1) 2022.10.13
boj 18112 이진수 게임  (2) 2022.09.16
boj 16946 벽 부수고 이동하기 4  (0) 2022.05.22
boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14

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

 

14466번: 소가 길을 건너간 이유 6

첫 줄에 N, K, R이 주어진다. 다음 R줄에는 한 줄에 하나씩 길이 주어진다. 길은 상하좌우로 인접한 두 목초지를 잇고, r c r′ c′의 형태 (행, 열, 행, 열)로 주어진다. 각 수는 1 이상 N 이하이다.

www.acmicpc.net

소는 인접한 좌표로 이동할 수 있지만 길로 지정된 경로로는 길을 건너야 갈 수 있습니다.

문제에서는 길을 건너지 않으면 만날 수 없는 소의 쌍을 구하므로 "길로 지정된 경로로는 이동할 수 없다"로 접근하면 되겠습니다.

 

저는 소 한마리씩 이동을 하고, 이동하는 도중에 다른 소를 만난다면 카운팅을 진행하고, 전체 소의 갯수에서 제외해주는 방식으로 해결하였습니다.

 

저의 로직입니다.

  1. 2차원 pair를 이용하여 길의 정보를 넣습니다. 이 때, 양방향으로 넣어줍니다.
  2. 소의 좌표는 map에 인덱스를 표시해주고, 벡터에 넣어줍니다.
  3. 소 한마리씩 bfs로 이동하며, 주어진 길 이외에 인접한 좌표로 모두 이동시킵니다.
  4. 주어진 길인지 확인하는 방법은 해당 좌표에 연결된 길을 하나하나 찾는 방법을 선택하였습니다.
  5. 이동하는 과정에서 다른 소를 만난다면 ret을 1 증가합니다.
  6. 전체 소에서 ret과 1을 뺀 값을 리턴합니다. (여기서 1은 본인을 제외하는 것입니다.)
  7. 쌍을 구하는 문제이므로 ans/2를 출력합니다.

저는 예제가 계속 맞지않아서..

"아니 전체에서 만난 애들 뺀거랑 애초에 못만난 애들을 구한거랑 같은데 왜 다르게 나오지? 그럼 나머지 애들은 뭔데"

를 반복했었는데..

소의 수는 M인데.. 전체를 N으로 잡아서 발생한 삽질이었습니다. ^^..

저와같은 삽질을 하는 분은 없겠죠..?

 

 

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
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#define MAX 101
using namespace std;
typedef pair<intint> pii;
 
vector<pii> list[MAX][MAX], v;
bool visit[MAX][MAX];
int map[MAX][MAX];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M, K;
 
int bfs(int sx, int sy) {
    queue<pii> q;
    visit[sx][sy] = true;
    q.push({ sx,sy });
    int num = map[sx][sy];
    int ret = 0;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        if (map[x][y] && map[x][y] != num) {
            ret++;
        }
 
        for (int i = 0; i < 4; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
 
            if (nx < 1 || ny < 1 || nx > N || ny > N) continue;
            if (visit[nx][ny]) continue;
 
            bool flag = true;
            for (auto a : list[x][y]) {
                if (a.first == nx && a.second == ny) {
                    flag = false;
                    break;
                }
            }
            if (!flag) continue;
 
            q.push({ nx,ny });
            visit[nx][ny] = true;
        }
    }
 
    return M - (ret + 1);
}
 
void func() {
    int ans = 0;
    int len = v.size();
    for (int i = 0; i < len; i++) {
        ans += bfs(v[i].first, v[i].second);
        memset(visit, 0sizeof(visit));
    }
 
    cout << ans / 2 << '\n';
}
 
void input() {
    int sx, sy, ex, ey;
    cin >> N >> M >> K;
    while (K--) {
        cin >> sx >> sy >> ex >> ey;
        list[sx][sy].push_back({ ex,ey });
        list[ex][ey].push_back({ sx,sy });
    }
 
    for (int i = 1; i <= M; i++) {
        cin >> sx >> sy;
        map[sx][sy] = i;
        v.push_back({ sx,sy });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 16985 Maaaaaaaaaze  (0) 2022.12.16
boj 18112 이진수 게임  (2) 2022.09.16
boj 16946 벽 부수고 이동하기 4  (0) 2022.05.22
boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14

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

 

18112번: 이진수 게임

첫 번째 줄에 길이 L의 ‘시작 이진수’가 주어진다. 두 번째 줄에 길이 K의 ‘목표 이진수’가 주어진다. (1 ≤ L, K ≤ 10)

www.acmicpc.net

  1. 맨 앞 숫자를 제외한 한 자리 숫자를 보수로 바꾸기
  2. 현재 수에 1 더하기
  3. 현재 수에 1 빼기 (현재 수가 자연수일 때만 해당)

위 과정을 반복하여 시작 이진수 s가 목표 이진수 e가 되는 최소 동작 횟수를 출력하는 문제로 오랜만에 bfs입니다.

입력은 10자리 이진수로 주어지며, 저는 이 수를 10진수로 변환하여 비트마스킹을 이용하였습니다.

 

이 풀이의 로직은

먼저, 이진수를 10진수로 변환하고, s를 시작으로 bfs 탐색합니다.

 

그 다음은 x가 0인 경우를 제외하고 한 비트씩 변경된 값을 queue에 넣습니다.

이 과정에서 bit가 x / 2보다 커진다면 마지막 비트이므로 break를 걸어줍니다.

 

e가 10자리 이진수이므로 1024보다 작은 수입니다.

따라서 x + 1이 1024보다 작은 경우에만 queue에 넣어주면 됩니다.

 

그리고 e는 음수가 아니므로 x가 자연수일 경우에만 x - 1을 queue에 넣어줍니다.

 

위의 과정을 반복하여 e에 도착하면 t를 리턴하여 출력합니다.

 

 

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
#include <iostream>
#include <queue>
#include <string>
#define MAX 10
using namespace std;
 
string str1, str2;
bool visit[1 << MAX];
int s, e;
 
int bfs() {
    queue<int> q;
    q.push(s);
    visit[s] = 1;
    for (int t = 0!q.empty(); t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front();
            q.pop();
 
            if (x == e) {
                return t;
            }
 
            int bit = 1;
            while (1) {
                if (!x) break;
                if (x & bit) {
                    if (bit > x / 2break;
                }
 
                int next = x ^ bit;
                if (!visit[next]) {
                    q.push(next);
                    visit[next] = true;
                }
                bit <<= 1;
            }
 
            if (x + 1 < 1024 && !visit[x + 1]) {
                q.push(x + 1);
                visit[x + 1= true;
            }
            if (x && !visit[x - 1]) {
                q.push(x - 1);
                visit[x - 1= true;
            }
        }
    }
 
    return 0;
}
 
void func() {
    cout << bfs() << '\n';
}
 
void init() {
    int len1 = str1.size();
    int mul = 1;
    for (int i = len1 - 1; i >= 0; i--) {
        if (str1[i] == '1') s += mul;
        mul <<= 1;
    }
 
    int len2 = str2.size();
    mul = 1;
    for (int i = len2 - 1; i >= 0; i--) {
        if (str2[i] == '1') e += mul;
        mul <<= 1;
    }
}
 
void input() {
    cin >> str1 >> str2;
    init();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 16985 Maaaaaaaaaze  (0) 2022.12.16
boj 14466 소가 길을 건너간 이유 6  (1) 2022.10.13
boj 16946 벽 부수고 이동하기 4  (0) 2022.05.22
boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14

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

 

16946번: 벽 부수고 이동하기 4

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이

www.acmicpc.net

값이 1인 칸을 0으로 변경했을 때 해당 칸에서 이동할 수 있는 칸의 수를 출력하는 문제입니다.

 

맵의 크기가 1000 * 1000이고, 모든 1의 칸을 대상으로 탐색하기에는 무조건 시간초과라는 생각이 들었고,

생각해낸 방법은 값이 0인 인접한 칸들에 넘버링을 부여한 후 넘버링의 크기를 더하는 방식입니다.

이것은 bfs를 통해 할 수 있습니다.

방문했던 모든 칸에 대해 넘버링과 카운팅을 합니다.

모든 인접한 칸들의 방문을 마쳤다면 해당 넘버링에 카운팅했던 수를 넣습니다.

 

그러면 남은 일은 값이 1인 칸에 대해 4방향 탐색하여 인접한 넘버링의 카운트를 모두 더하는 일입니다.

[boj 16932 모양만들기(링크)]에서 하나의 칸을 변경하여 만들 수 있는 모양의 최대 크기를 구한 적이 있습니다.

이 방식과 동일하게 접근하고, 중복된 칸을 예외처리 하기 위해 set을 사용합니다.

 

 

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
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#define MAX 1001
#define MOD 10
using namespace std;
typedef pair<intint> pi;
 
char list[MAX][MAX];
bool visit[MAX][MAX];
int num[MAX][MAX], ans[MAX][MAX];
int numSize[MAX * MAX];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M;
 
void func() {
    set<int> s;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (list[i][j] == '0'continue;
 
            int sum = 0;
            for (int d = 0; d < 4; d++) {
                int nx = i + direct[d][0];
                int ny = j + direct[d][1];
 
                if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
                if (list[nx][ny] != '0'continue;
                if (s.find(num[nx][ny]) != s.end()) continue;
 
                sum += numSize[num[nx][ny]];
                s.insert(num[nx][ny]);
            }
 
            ans[i][j] = (sum + 1) % MOD;
            s.clear();
        }
    }
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cout << ans[i][j];
        }
        cout << '\n';
    }
}
 
void bfs(int sx, int sy, int n) {
    queue<pi> q;
    q.push({ sx,sy });
    visit[sx][sy] = true;
    int cnt = 0;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        
        cnt++;
        num[x][y] = n;
        for (int i = 0; i < 4; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
            
            if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
            if (visit[nx][ny] || list[nx][ny] == '1'continue;
 
            q.push({ nx,ny });
            visit[nx][ny] = true;
        }
    }
 
    numSize[n] = cnt;
}
 
void init() {
    int n = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (visit[i][j] || list[i][j] == '1'continue;
 
            bfs(i, j, n++);
        }
    }
}
 
void input() {
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 14466 소가 길을 건너간 이유 6  (1) 2022.10.13
boj 18112 이진수 게임  (2) 2022.09.16
boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14
boj 17244 아맞다우산  (0) 2021.11.25

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

 

5547번: 일루미네이션

첫째 줄에 두 개의 정수 W와 H가 주어진다. (1 ≤ W, H ≤ 100) 다음 H줄에는 상근이네 집의 건물 배치가 주어진다. i+1줄에는 W개의 정수가 공백으로 구분되어 있다. j번째 (1 ≤ j ≤ w) 정수의 좌표는

www.acmicpc.net

 

위 그림의 좌표와 상관없이 저는 (1, 1) ~ (N, M)으로 입력을 받았습니다.

나중에 x의 좌표에 따라 인접하는 좌표들만 구분하면 되는 것입니다.

 

이 문제의 핵심은 건물 외부 체크를 어떻게 하느냐입니다.

왼쪽 건물들을 보시면 내부에도 흰색이 존재합니다. 이거를 잘 걸러내야 합니다.

 

저는 배열의 크기를 (N + 2, M + 2)로 설계하였고,

(1, 1) ~ (N, M)에 건물 정도를 입력 받아 가장자리에 있는 좌표에는 모두 건물 외부가 올 수 있게끔 하였습니다.

(0, 0)이나 (N + 1, M + 1)에 있는 것은 무조건 건물 외부 (흰색) 입니다.

그러면 무조건 흰색이 되는 (0, 0)을 시작으로 bfs를 돌려 건물 외부들을 모두 체크할 수있습니다.

 

이후 건물을 bfs로 순회하여 각 좌표에서 인접한 건물이 몇 개 있는지 세어 줍니다.

이 때, 건물 외부의 흰색은 카운팅을 하지 않으며, 건물 내부의 흰색은 카운팅을 합니다.

그래야 건물 내부에도 조명을 설치하지 않습니다. [위 사진 기준 (2, 3)이 예시입니다.]

 

카운팅이 완료되었으면 해당 좌표에서 조명을 설치할 벽면의 길이를 구합니다.

벽면의 길이는 인접한 건물이 0개 ~ 6개인 경우가 동일하므로 직접 그려보시면 알 수 있습니다.

 

 

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
#include <iostream>
#include <algorithm>
#include <queue>
#define MAX 103
#define LEN 6
using namespace std;
typedef pair<intint> pi;
 
int list[MAX][MAX];
bool visit[MAX][MAX], sideChk[MAX][MAX];
int direct[2][6][2= {
    {{-1,-1},{-1,0},{0,1},{1,0},{1,-1},{0,-1}},
    {{0,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0}}
};
int len[7];
int N, M, ans;
 
void sideBfs(int sx, int sy) {
    queue<pi> q;
    q.push({ sx,sy });
    sideChk[sx][sy] = true;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        int idx = x % 2;
        for (int d = 0; d < 6; d++) {
            int nx = x + direct[idx][d][0];
            int ny = y + direct[idx][d][1];
 
            if (nx < 0 || ny < 0 || nx > N + 1 || ny > M + 1continue;
            if (list[nx][ny] || sideChk[nx][ny]) continue;
 
            q.push({ nx,ny });
            sideChk[nx][ny] = true;
        }
    }
}
 
void bfs(int sx, int sy) {
    queue<pi> q;
    q.push({ sx,sy });
    visit[sx][sy] = true;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        int cnt = 0;
        int idx = x % 2;
        for (int d = 0; d < 6; d++) {
            int nx = x + direct[idx][d][0];
            int ny = y + direct[idx][d][1];
 
            if (nx <= 0 || ny <= 0 || nx > N + 1 || ny > M + 1continue;
            if (!list[nx][ny]) {
                if (!sideChk[nx][ny]) cnt++;
                continue;
            }
            cnt++;
            if (visit[nx][ny]) continue;
 
            q.push({ nx,ny });
            visit[nx][ny] = true;
        }
 
        ans += len[cnt];
    }
}
 
void func() {
    sideBfs(00);
 
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (!list[i][j] || visit[i][j]) continue;
 
            bfs(i, j);
        }
    }
 
    cout << ans << '\n';
}
 
void init() {
    for (int i = 0; i <= LEN; i++) {
        len[i] = LEN - i;
    }
}
 
void input() {
    cin >> M >> N;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    init();
    input();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 18112 이진수 게임  (2) 2022.09.16
boj 16946 벽 부수고 이동하기 4  (0) 2022.05.22
boj 16932 모양 만들기  (0) 2022.05.14
boj 17244 아맞다우산  (0) 2021.11.25
boj 1194 달이 차오른다, 가자.  (0) 2021.04.21

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

 

16932번: 모양 만들기

N×M인 배열에서 모양을 찾으려고 한다. 배열의 각 칸에는 0과 1 중의 하나가 들어있다. 두 칸이 서로 변을 공유할때, 두 칸을 인접하다고 한다. 1이 들어 있는 인접한 칸끼리 연결했을 때, 각각의

www.acmicpc.net

정말 오랜만에 알고리즘 포스팅입니다.

 

이 문제는 배열의 값이 0인 한 칸을 1로 변경하여 만들 수 있는 모양의 최대 크기를 구하는 문제입니다.

이 문제에서 모양이란 배열 내에서 1로 이루어진 연결 요소입니다.

 

저는 bfs를 통해 1로 이루어진 모양들을 넘버링하여 해당 넘버링의 크기를 vector에 넣어주었고,

브루트포스를 통해 값이 0인 칸들의 인접한 칸들의 크기 합을 구해 max를 구하였습니다.

이 때, 인접한 칸에서 같은 넘버링이 나올 수 있으므로 중복체크를 위해 set을 사용하였습니다.

 

넘버링했다는 것은

0 1 1
0 0 1
0 1 0

이렇게 되어있는 배열을

0 1 1
0 0 1
0 2 0

이렇게 모양별로 구분할 수 있도록 변경하였습니다.

이 상태에서 브루트포스로 모양들을 연결해주는 것입니다.

 

여기서 인접한 칸에서 같은 넘버링이 나오는 경우는 좌표 (1, 1)을 보시면 이해하실 수 있습니다.

0 1 1
0 0 1
0 2 0
(1, 1)을 1로 변경한다고 했을 때 위(0, 1)와 오른쪽(1, 2)은 같은 넘버링을 가진 모양입니다.
이미 같은 모양에 속하므로 이를 중복으로 더해서는 안됩니다.
따라서 중복체크를 위해 set을 사용하였습니다.

 

 

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
#include <iostream>
#include <queue>
#include <vector>
#include <set>
#define MAX 1001
using namespace std;
typedef pair<intint> pi;
 
int list[MAX][MAX];
bool visit[MAX][MAX];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
vector<int> sizeList;
int N, M;
 
void bfs(int sx, int sy, int num) {
    int ret = 0;
    queue<pi> q;
    q.push({ sx,sy });
    visit[sx][sy] = true;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        ret++;
        list[x][y] = num;
 
        for (int i = 0; i < 4; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
 
            if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
            if (!list[nx][ny] || visit[nx][ny]) continue;
 
            q.push({ nx,ny });
            visit[nx][ny] = true;
        }
    }
 
    sizeList.push_back(ret);
}
 
void func() {
    sizeList.push_back(0);
    int num = 1;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (!list[i][j] || visit[i][j]) continue;
 
            bfs(i, j, num++);
        }
    }
 
    int ans = 0;
    set<int> s;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (list[i][j]) continue;
 
            int ret = 0;
            for (int d = 0; d < 4; d++) {
                int nx = i + direct[d][0];
                int ny = j + direct[d][1];
 
                if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
                if (!list[nx][ny]) continue;
                if (s.find(list[nx][ny]) != s.end()) continue;
 
                s.insert(list[nx][ny]);
                ret += sizeList[list[nx][ny]];
            }
 
            ans = max(ans, ret + 1);
            s.clear();
        }
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 16946 벽 부수고 이동하기 4  (0) 2022.05.22
boj 5547 일루미네이션  (0) 2022.05.15
boj 17244 아맞다우산  (0) 2021.11.25
boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 17471 게리맨더링  (0) 2021.04.16

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

 

17244번: 아맞다우산

경재씨는 저녁 약속을 가기 전 챙기지 않은 물건들이 있는 지 확인하고 있다. 필요한 물건은 전부 챙긴 것 같았고 외출 후 돌아오는 길에 경재씨는 외쳤다. "아 맞다 우산!!!" 경재 씨는 매번 외출

www.acmicpc.net

챙겨야 하는 물건은 최대 5개이므로 bfs + 비트마스킹이 가능합니다.

visit[x][y][bit]: 좌표 (x, y)에 도착했을 때 찾은 물건의 비트가 bit인 경우의 방문 처리입니다.

비트를 어떻게 할지 고민하다가 chk배열을 사용하여 해당 좌표에 있는 물건의 비트를 정해주었습니다.

나가는 문에 도착했을 때 모든 물건을 찾았을 때만 t를 출력합니다.

 

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
#include <iostream>
#include <queue>
#define MAX 50
using namespace std;
typedef pair<pair<intint>int> pii;
 
queue<pii> q;
char list[MAX][MAX];
bool visit[MAX][MAX][1 << 5];
int chk[MAX][MAX];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M, bit;
 
void bfs() {
    for (int t = 1!q.empty(); t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().first.first;
            int y = q.front().first.second;
            int cnt = q.front().second;
            q.pop();
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
                int ncnt = cnt;
 
                if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
                if (list[nx][ny] == 'X') {
                    int b = chk[nx][ny];
 
                    ncnt |= b;
                }
                if (list[nx][ny] == '#' || visit[nx][ny][ncnt]) continue;
 
                if (list[nx][ny] == 'E' && ncnt == bit) {
                    cout << t << '\n';
                    return;
                }
 
                q.push({ {nx,ny}, ncnt });
                visit[nx][ny][ncnt] = true;
            }
        }
    }
}
 
void input() {
    int cnt = 0;
    cin >> M >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> list[i][j];
            if (list[i][j] == 'S') {
                q.push({ {i,j},0 });
                visit[i][j][0= true;
            }
            else if (list[i][j] == 'X') {
                chk[i][j] = (1 << cnt);
                cnt++;
            }
        }
    }
 
    bit = (1 << cnt) - 1;
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    bfs();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14
boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 17471 게리맨더링  (0) 2021.04.16
boj 2573 빙산  (0) 2021.04.05

www.acmicpc.net/problem/1194

 

1194번: 달이 차오른다, 가자.

첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고,

www.acmicpc.net

기본적인 bfs에 비트마스킹이 더해진 문제입니다.

 

visit[x][y][key] : (x, y)에 도달했을 때 갖고있는 열쇠 종류

문을 열기 위해서는 열쇠를 갖고있어야 하므로 얻은 열쇠를 비트마스킹을 이용하여 관리합니다.

 

로직은 다른 bfs와 똑같이 돌아가며, 확인해야할 조건은

1. 맵 밖으로 나갈 경우

2. 문을 만났을 경우

3. 열쇠를 만났을 경우

4. 해당 좌표를 이미 방문한 경우

5. 벽을 만난 경우

 

1, 4, 5인 경우에는 continue를 해주시면 되고,

2인 경우에는 열쇠가 없는 경우에만 continue를 해주시면 됩니다.

3인 경우에는 열쇠를 추가합니다.

 

탈출에 성공하였으면 현재 시간을 출력해주시고, 큐가 비었는데도 탈출하지 못했으면 -1을 출력합니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Deque<int[]> dq = new ArrayDeque<>();
    static char list[][] = new char[51][51];
    static boolean visit[][][] = new boolean[51][51][64];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M;
 
    static void bfs() {
        for (int t = 0!dq.isEmpty(); t++) {
            int size = dq.size();
            while (size-- > 0) {
                int x = dq.peek()[0];
                int y = dq.peek()[1];
                int key = dq.poll()[2];
 
                if (list[x][y] == '1') {
                    System.out.println(t);
                    return;
                }
                for (int i = 0; i < 4; i++) {
                    int nx = x + direct[i][0];
                    int ny = y + direct[i][1];
                    int nextKey = key;
 
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                        continue;
                    if ('A' <= list[nx][ny] && list[nx][ny] <= 'F') {
                        int door = list[nx][ny] - 'A';
 
                        if ((key & (1 << door)) == 0)
                            continue;
                    }
                    if ('a' <= list[nx][ny] && list[nx][ny] <= 'f') {
                        nextKey = nextKey | (1 << (list[nx][ny] - 'a'));
                    }
 
                    if (visit[nx][ny][nextKey] || list[nx][ny] == '#')
                        continue;
                    dq.add(new int[] { nx, ny, nextKey });
                    visit[nx][ny][nextKey] = true;
                }
            }
        }
        
        System.out.println(-1);
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            list[i] = st.nextToken().toCharArray();
            for (int j = 0; j < M; j++) {
                if (list[i][j] == '0') {
                    dq.add(new int[] { i, j, 0 });
                    visit[i][j][0= true;
                }
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        bfs();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 16932 모양 만들기  (0) 2022.05.14
boj 17244 아맞다우산  (0) 2021.11.25
boj 17471 게리맨더링  (0) 2021.04.16
boj 2573 빙산  (0) 2021.04.05
boj 14923 미로 탈출  (0) 2021.03.29

www.acmicpc.net/problem/17471

 

17471번: 게리맨더링

선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

www.acmicpc.net

선거구를 두 구간으로 나누는데 나눠진 구간끼리 연결되어 있어야합니다.

 

dfs기반의 부분집합으로 나눌 수 있는 모든 구간을 확인합니다.

두 구간을 div1, div2라는 리스트를 사용하였고, 구역들끼리 연결되어있는지 bfs를 통해 확인합니다.

구간의 모든 구역끼리 연결되어 있으면 구역들의 합의 최솟값을 갱신합니다.

두 선거구로 나눌 수 없는 경우가 입력으로 주어질 수 있으니 그 때는 -1을 출력합니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static ArrayList<Integer> graph[] = new ArrayList[11];
    static ArrayList<Integer> div1 = new ArrayList<>();
    static ArrayList<Integer> div2 = new ArrayList<>();
    static int list[] = new int[11];
    static boolean pick[] = new boolean[11];
    static boolean visit[] = new boolean[11];
    static int N, ans = 2147483647;
 
    static boolean bfs(ArrayList<Integer> div, int size, boolean t) {
        Arrays.fill(visit, false);
        Deque<Integer> dq = new ArrayDeque<>();
        dq.add(div.get(0));
        visit[div.get(0)] = true;
        int cnt = 0;
        while (!dq.isEmpty()) {
            int x = dq.poll();
            cnt++;
            for (int i = 0; i < graph[x].size(); i++) {
                int next = graph[x].get(i);
 
                if (visit[next] || pick[next] != t)
                    continue;
 
                visit[next] = true;
                dq.add(next);
            }
        }
 
        if (cnt == size)
            return true;
        else
            return false;
    }
 
    static void func(int idx) {
        if (!div1.isEmpty()) {
            for (int i = 1; i <= N; i++) {
                if (!pick[i])
                    div2.add(i);
            }
            
            if(!div2.isEmpty()) {
                if (bfs(div1, div1.size(), true)) {
                    if (bfs(div2, div2.size(), false)) {
                        int sum = 0;
                        for (int i = 0; i < div1.size(); i++) {
                            sum += list[div1.get(i)];
                        }
 
                        for (int i = 0; i < div2.size(); i++) {
                            sum -= list[div2.get(i)];
                        }
 
                        ans = Math.min(ans, Math.abs(sum));
                    }
                }
                div2.clear();
            }
        }
 
        for (int i = idx; i <= N; i++) {
            div1.add(i);
            pick[i] = true;
            func(i + 1);
            pick[i] = false;
            div1.remove(div1.size() - 1);
        }
    }
 
    static void input() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
 
        int K, v;
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            K = Integer.parseInt(st.nextToken());
            graph[i] = new ArrayList<>();
            while (K-- > 0) {
                v = Integer.parseInt(st.nextToken());
                graph[i].add(v);
            }
        }
    }
 
    static void print() {
        if (ans == 2147483647)
            System.out.println(-1);
        else
            System.out.println(ans);
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func(1);
        print();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 17244 아맞다우산  (0) 2021.11.25
boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 2573 빙산  (0) 2021.04.05
boj 14923 미로 탈출  (0) 2021.03.29
boj 17836 공주님을 구해라!  (0) 2021.03.26

www.acmicpc.net/problem/2573

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

먼저 빙산 주위에 바다가 있는 위치 수만큼 빙산이 녹습니다.

 

이중for문으로 이거를 확인해주시면 되고, 주위에 바다가 있을 때마다 cnt[i][j]를 1씩 늘려줍니다.

그 다음 이중for문을 다시 돌려서 cnt[i][j]만큼 빙산을 녹여줍니다.

 

빙산을 녹이는 과정에서 빙산이 두 덩어리 이상으로 분리가 되면 그 시간을 출력해주시면 됩니다.

이 과정을 bfs로 구현하였습니다. 이중for문을 돌면서 방문안된 빙산을 발견하면 bfs를 호출하는데

만약 두 번째로 bfs에 들어가게 되면 빙산이 분리가 되었다는 말이 되기때문에 바로 시간을 출력해주시면 됩니다.

 

저는 문제를 읽어보니 최초로 주어지는 입력에는 무조건 빙산이 한 덩어리라는 조건이 없어서

빙산이 두 덩어리 이상으로 분리가 되었는지 체크하는 bfs함수를 먼저 호출하였습니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int list[][] = new int[300][300];
    static int cnt[][] = new int[300][300];
    static boolean visit[][] = new boolean[300][300];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M;
 
    static void init() {
        for (int i = 0; i < N; i++)
            Arrays.fill(visit[i], false);
    }
 
    static void bfs(int sx, int sy) {
        Deque<int[]> dq = new ArrayDeque<>();
        dq.add(new int[] { sx, sy });
        visit[sx][sy] = true;
        while (!dq.isEmpty()) {
            int x = dq.peek()[0];
            int y = dq.poll()[1];
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
 
                if (visit[nx][ny] || list[nx][ny] == 0)
                    continue;
 
                dq.add(new int[] { nx, ny });
                visit[nx][ny] = true;
            }
        }
    }
 
    static void func() {
        for (int t = 0;; t++) {
            boolean chk = false;
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0 || visit[i][j])
                        continue;
                    if (chk) {
                        System.out.println(t);
                        return;
                    }
                    bfs(i, j);
                    chk = true;
                }
            }
 
            if (!chk) {
                System.out.println(0);
                return;
            }
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0)
                        continue;
                    for (int k = 0; k < 4; k++) {
                        int nx = i + direct[k][0];
                        int ny = j + direct[k][1];
 
                        if (list[nx][ny] == 0)
                            cnt[i][j]++;
                    }
                }
            }
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0)
                        continue;
                    list[i][j] = list[i][j] >= cnt[i][j] ? list[i][j] - cnt[i][j] : 0;
                    cnt[i][j] = 0;
                }
            }
            
            init();
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 17471 게리맨더링  (0) 2021.04.16
boj 14923 미로 탈출  (0) 2021.03.29
boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25

www.acmicpc.net/problem/14923

 

14923번: 미로 탈출

홍익이는 사악한 마법사의 꾐에 속아 N x M 미로 (Hx, Hy) 위치에 떨어졌다. 다행히도 홍익이는 마법사가 만든 미로의 탈출 위치(Ex, Ey)를 알고 있다. 하지만 미로에는 곳곳에 마법사가 설치한 벽이

www.acmicpc.net

(hx, hy)에서 출발하여 (ex, ey)까지 갈 수 있는 최단거리를 출력합니다.

맵에는 벽이 있으며 벽을 1개까지 부술 수 있습니다.

 

www.acmicpc.net/problem/2206

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로

www.acmicpc.net

이 문제와 같은 풀이방식입니다.

이 문제와 다른점은 출발점과 도착점이 고정이 아니라는 점입니다.

 

visit[x][y][cnt] : (x, y)에 벽을 부수고 방문한 경우와 안부수고 방문한 경우를 나눠줍니다.

 

탈출이 가능하면 거리를 출력, 불가능하면 -1을 출력합니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Deque<int[]> dq = new ArrayDeque<>();
    static int list[][] = new int[1001][1001];
    static boolean visit[][][] = new boolean[1001][1001][2];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M, ex, ey;
 
    static void bfs() {
        for (int t = 1;; t++) {
            int size = dq.size();
            while (size-- > 0) {
                int x = dq.peek()[0];
                int y = dq.peek()[1];
                int cnt = dq.poll()[2];
 
                for (int i = 0; i < 4; i++) {
                    int nx = x + direct[i][0];
                    int ny = y + direct[i][1];
 
                    if (nx < 1 || ny < 1 || nx > N || ny > M)
                        continue;
                    if (list[nx][ny] == 1) {
                        if (cnt > 0 || visit[nx][ny][1])
                            continue;
 
                        dq.add(new int[] { nx, ny, 1 });
                        visit[nx][ny][1= true;
                    } else {
                        if (visit[nx][ny][cnt])
                            continue;
 
                        dq.add(new int[] { nx, ny, cnt });
                        visit[nx][ny][cnt] = true;
 
                        if (nx == ex && ny == ey) {
                            System.out.println(t);
                            return;
                        }
                    }
                }
            }
 
            if (dq.isEmpty()) {
                System.out.println(-1);
                return;
            }
        }
    }
 
    static void input() throws Exception {
        int x, y;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        x = Integer.parseInt(st.nextToken());
        y = Integer.parseInt(st.nextToken());
        dq.add(new int[] { x, y, 0 });
        visit[x][y][0= true;
 
        st = new StringTokenizer(br.readLine());
        x = Integer.parseInt(st.nextToken());
        y = Integer.parseInt(st.nextToken());
        ex = x;
        ey = y;
 
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        bfs();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 17471 게리맨더링  (0) 2021.04.16
boj 2573 빙산  (0) 2021.04.05
boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25
boj 1600 말이 되고픈 원숭이  (0) 2021.03.24

www.acmicpc.net/problem/17836

 

17836번: 공주님을 구해라!

용사는 마왕이 숨겨놓은 공주님을 구하기 위해 (N, M) 크기의 성 입구 (1,1)으로 들어왔다. 마왕은 용사가 공주를 찾지 못하도록 성의 여러 군데 마법 벽을 세워놓았다. 용사는 현재의 가지고 있는

www.acmicpc.net

시작점 : (1, 1)

도착점 : (N, M)

제한 시간 : T

무기가 없으면 벽을 지나갈 수 없지만 무기가 있으면 모든 벽을 부수고 지나갈 수 있습니다.


visit[x][y][chk] : x, y에 도달했을 때 무기를 가진 상태로 방문했는지 여부

 

1. 다음 칸이 무기가 있는 칸일 경우(list[nx][ny] = 2)

- 무기를 획득하였으므로 chk=true인 값을 큐에 넣어줍니다.

2. 다음 칸이 벽이 아니고 방문하지 않았을 경우

- 평상시 bfs처럼 다음 정점을 큐에 넣고 방문체크합니다.

3. 다음 칸이 벽이고 무기를 가진 상태인 경우

- 무기를 갖고있으면 어디든 지나갈 수 있으므로 2번과 같은 로직을 수행합니다.

 

도착지점인 (N, M)의 값은 0이므로 2, 3번에서 (N, M)에 도달하였으면 현재 시간을 출력합니다.

만약 T시간 동안 (N, M)에 도달하지 못하면 Fail을 출력합니다.

 

 

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
#include <iostream>
#include <queue>
using namespace std;
 
typedef struct Point {
    int x;
    int y;
    bool chk;
};
 
queue<Point> q;
bool visit[101][101][2];
int list[101][101];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M, T;
 
void bfs() {
    q.push({ 1,1,false });
    visit[1][1][0= true;
    for (int t = 1; t <= T; t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().x;
            int y = q.front().y;
            bool chk = q.front().chk;
            q.pop();
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
 
                if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
                if (list[nx][ny] == 2 && !visit[nx][ny][1]) {
                    q.push({ nx,ny,true });
                    visit[nx][ny][1= true;
                }
                else if (list[nx][ny] == 0 && !visit[nx][ny][chk]) {
                    q.push({ nx,ny,chk });
                    visit[nx][ny][chk] = true;
                    if (nx == N && ny == M) {
                        cout << t << '\n';
                        return;
                    }
                }
                else if (list[nx][ny] == 1 && chk && !visit[nx][ny][chk]) {
                    q.push({ nx,ny,chk });
                    visit[nx][ny][chk] = true;
                    if (nx == N && ny == M) {
                        cout << t << '\n';
                        return;
                    }
                }
            }
        }
    }
 
    cout << "Fail\n";
}
 
void input() {
    cin >> N >> M >> T;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    bfs();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 2573 빙산  (0) 2021.04.05
boj 14923 미로 탈출  (0) 2021.03.29
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25
boj 1600 말이 되고픈 원숭이  (0) 2021.03.24
boj 2589 보물섬  (0) 2021.03.16

+ Recent posts