짱아의 개발 기록장

백준 17472번. 다리 만들기2(c++) / BFS+유니온파인드 본문

Algorithm/Baekjoon

백준 17472번. 다리 만들기2(c++) / BFS+유니온파인드

jungahshin 2021. 3. 29. 23:30
반응형

설명 추가 예정

 

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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <iostream>
#include <queue>
#include <vector>
#include <climits>
#include <tuple>
#include <algorithm>
using namespace std;
 
int n, m;
int connect[7= { 0, };
int map[11][11= { 0, };
int dx[4= { 00-11 };
int dy[4= { -1100 };
int check[11][11= { 0, }; // 영역 표시하기
vector<pair<intint>> edge[7];
int areaNum = 0;
vector<int> seq; // 다리를 만드는 순서
 
int find(int i)
{
    if (i == connect[i]) {
        return i;
    }
 
    return connect[i] = find(connect[i]);
}
 
int makeBridge()
{
    int ans = 0// 총 다리의 길이
 
    // from -> to 를 잇는 다리 건설
    for (int i = 0; i < seq.size(); i++) {
        int from = seq[i];
        queue<tuple<intintintint>> q;
        for (int k = 0; k < edge[from].size(); k++) {
            for (int t = 0; t < 4; t++) {
                q.push(make_tuple(edge[from][k].first, edge[from][k].second, 0, t));
            }
        }
 
        while (!q.empty()) {
            int x, y, cnt, dir;
            tie(x, y, cnt, dir) = q.front();
            q.pop();
 
            int nx = x + dx[dir];
            int ny = y + dy[dir];
            if (0 <= nx && nx < n && 0 <= ny && ny < m && check[nx][ny] != from) {
                if (map[nx][ny] == 0) {
                    q.push(make_tuple(nx, ny, cnt + 1, dir));
                }
                else {
                     //from -> to 다리를 이을 수 있으면 잇는다.
                    int to = check[nx][ny];
                    int a = find(from);
                    int b = find(to);
                    if (a==|| cnt<2continue;
                    connect[a] = b;
                    ans += cnt;
                }
            }
        }
    }
 
    return ans;
}
 
void makeArea()
{
    int ans = INT_MAX;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (map[i][j] == 0continue;
            if (check[i][j] != 0continue;
            int visited[11][11= { 0, };
            areaNum++;
            queue<pair<intint>> q;
            q.push(make_pair(i, j));
 
            while (!q.empty()) {
                int x = q.front().first;
                int y = q.front().second;
                q.pop();
                visited[x][y] = true;
                check[x][y] = areaNum;
 
                for (int k = 0; k < 4; k++) {
                    int nx = x + dx[k];
                    int ny = y + dy[k];
                    if (0 <= nx && nx < n && 0 <= ny && ny < m && !visited[nx][ny]) {
                        visited[nx][ny] = true;
                        if (map[nx][ny] == 0) {
                            edge[check[x][y]].push_back(make_pair(x, y));
                        }
                        if (map[nx][ny] == 1) {
                            q.push(make_pair(nx, ny));
                        }
                    }
                }
            }
        }
    }
}
 
bool isAllConnect()
{
    for (int i = 1; i < areaNum; i++) {
        if (find(i) != find(i + 1)) return false;
    }
 
    return true;
}
 
int main()
{
    cin >> n>>m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
        }
    }
    
    int ans = INT_MAX;
    bool isPossible = false// 모든 섬을 연결하는 것이 가능한지
                             
    // 영역 표시
    makeArea();
 
    // Brute Force로 최단 다리 구하기
    for (int i = 1; i <= areaNum; i++) {
        seq.push_back(i);
    }
    do {
        for (int i = 1; i <= areaNum; i++) {
            connect[i] = i;
        }
        int num = makeBridge();
        if (isAllConnect()) {
            isPossible = true;
            ans = min(ans, num);
        }
    } while (next_permutation(seq.begin(), seq.end()));
 
    if (isPossible) {
        cout << ans << "\n";
    }
    else {
        cout << "-1" << "\n";
    }
 
    return 0;
}
cs
반응형
Comments