ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 17472번 다리 만들기2
    PS 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;
    }

     

     

     

     

    'PS' 카테고리의 다른 글

    백준 16953번 A->B  (0) 2020.03.07
    백준 2151번 거울 설치  (0) 2020.03.07
    백준 17471번 게리맨더링  (0) 2020.03.05
    백준 1022번 소용돌이 예쁘게 출력하기  (0) 2020.03.03
    벡준 16939번 2x2x2 큐브  (0) 2020.03.03
Designed by Tistory.