PS
백준 17472번 다리 만들기2
남마허
2020. 3. 5. 19:51
https://www.acmicpc.net/problem/17472
17472번: 다리 만들기 2
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.
www.acmicpc.net
<접근방법>
https://www.acmicpc.net/problem/1260
문제에 대한 감이 아예 안오시면 이 문제를 완전히 이해해야 합니다.
기본적인 그래프 이론 문제입니다.
다리를 연결하는 방법을 전부 고려해야하는 완전 탐색 문제입니다.
우선 n개의 섬을 전부 연결하기 위해서는 최소 n-1개의 다리가 필요합니다.
즉, 다리 n-1개를 선택해야 합니다.
조합으로 선택하면 됩니다.
다리를 선택한 후, 모든 섬이 이어져 있는지 확인해야 합니다.
아무 섬에서 시작하여 bfs를 돌면 확인할 수 있겠죠.
연결여부가 확인되면 최소의 가중치인지 확인하면 됩니다.
섬에 번호 붙이기, 가중치 구하기, 연결성 확인...
접근보다는 구현이 어려운 문제였습니다.
<느낀 점>
<코드>
코드에 사족이 많습니다...ㅎㅎ
#include <iostream>
#include <algorithm>
#include <queue>
#include <memory.h>
using namespace std;
struct point {
int y, x;
};
const int INF = 987654321;
int n, m, num;
int map[11][11], graph[11][11], w[11][11];
bool selected[11][11];
int dy[4] = { 1, -1, 0, 0 };
int dx[4] = { 0, 0, 1, -1 };
int res = INF;
void labeling() {
queue<point> q;
bool visit[10][10] = {false, };
num = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 1 && !visit[i][j]) {
q.push({i, j});
visit[i][j] = true;
while (!q.empty()) {
point t = q.front();
q.pop();
graph[t.y][t.x] = num;
for (int k = 0; k < 4; k++) {
int ty = t.y + dy[k];
int tx = t.x + dx[k];
if (ty < 0 || ty >= n || tx < 0 || tx >= m) continue;
if (map[ty][tx] == 0 || visit[ty][tx]) continue;
graph[ty][tx] = num;
q.push({ty, tx});
visit[ty][tx] = true;
}
}
num++;
}
}
}
num--;
}
void distance(int y, int x) {
int start = graph[y][x];
for (int i = 0; i < 4; i++) {
int ty = y;
int tx = x;
int len = 0;
int next;
while (1) {
ty += dy[i];
tx += dx[i];
if (ty < 0 || ty >= n || tx < 0 || tx >= m) break;
if (graph[ty][tx] == start) break;
next = graph[ty][tx];
if (next != 0) {
if (len >= 2) {
w[start][next] = min(w[start][next], len);
}
break;
}
len++;
}
}
}
void cal_weight() {
for (int i = 1; i <= num; i++) {
for (int j = 1; j <= num; j++) {
w[i][j] = INF;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (graph[i][j] != INF) {
distance(i, j);
}
}
}
for (int i = 1; i <= num; i++) {
for (int j = 1; j <= num; j++) {
if (w[i][j] == INF) {
w[i][j] = 0;
}
}
}
}
bool check() {
queue<int> q;
bool visit[10] = { false, };
int cnt = 0;
q.push(1);
visit[1] = true;
while (!q.empty()) {
int now = q.front();
q.pop();
cnt++;
for (int i = 1; i <= num; i++) {
if (visit[i]) continue;
if (selected[now][i]) {
q.push(i);
visit[i] = true;
}
}
}
if (cnt == num) return true;
return false;
}
void dfs(int dep, int start, int W) {
if (dep == num - 1) {
if (check()) {
res = min(res, W);
}
return;
}
for (int i = start; i < num*num; i++) {
int y = i / num + 1;
int x = i % num + 1;
if (y <= x) continue;
if (w[y][x] != 0) {
selected[y][x] = true;
selected[x][y] = true;
dfs(dep + 1, i + 1, W + w[y][x]);
selected[y][x] = false;
selected[x][y] = false;
}
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
}
}
labeling();
cal_weight();
dfs(0, 0, 0);
if (res == INF) cout << -1 << '\n';
else cout << res << '\n';
return 0;
}
반응형