반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 처우산정
- 처우협의
- 물채우기
- upper_bound
- 백준
- 성적평가
- Docker
- dfs
- compose
- 매개변수탐색
- incr
- 6987
- 연결요소
- BOJ
- 13908
- 경력
- 오퍼레터
- OFFSET
- 이분탐색
- 파라메트릭
- 기술면접
- softeer
- BFS
- Kafka
- 퇴사통보
- msSQL
- 소프티어
- 백트래킹
- boj #19237 #어른 상어
- @P0
Archives
- Today
- Total
기술 블로그
17472번 다리 만들기 2 본문
728x90
반응형
https://www.acmicpc.net/problem/17472
1. DFS로 각 섬을 Group화 한다.(1, 2, 3, ...)
2. BFS로 각 정점끼리의 거리를 구하는데 이 때, 4가지 방향(동서남북)에 대한 배열(코드의 vertex)을
활용해야 한다. 이유는 아래 예제를 생각해보자.
(주의 : 나의 코드에서는 방문 처리를 말하는 것이 아니다.
다른 방법으로 방문 처리를 4가지 방향으로 해도 된다. 단순 이 글에서의 설명이다.)
1 2 3 4 5 6 | 5 10 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 | cs |
3. MST로 활용하기 위해, mst vector에 {간선의 가중치, 현재 정점, 다음 정점}을 담는다.
4. 간선의 가중치를 기준으로 오름차순한다.
5. 사이클 방지를 위해 Union-Find를 활용한다.
6. MST 특성상 최소 다리 개수는 전체 정점 개수 - 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 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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | #include <bits/stdc++.h> using namespace std; #define Max 11 #define INF 987654321 // bfs를 위한 구조체 typedef struct info { int y, x, d; }info; // mst를 위한 구조체 typedef struct info2 { int w, here, next; }info2; int m[Max][Max], N, M, answer, gc = 1, parent[Max], vertex[Max][4]; int dy[4] = { 0, 1, 0, -1 }; int dx[4] = { 1, 0, -1, 0 }; vector<pair<int, int> > v[Max]; vector<info2> mst; bool visit[Max][Max]; bool cmp(const info2 & a, const info2 & b) { if (a.w < b.w) return true; return false; } // 그룹화 void dfs(int r, int c, int group) { visit[r][c] = true; m[r][c] = group; for (int i = 0; i < 4; i++) { int y = r + dy[i]; int x = c + dx[i]; if (y < 0 || y >= N || x < 0 || x >= M || visit[y][x] || !m[y][x]) continue; dfs(y, x, group); } } // 각 정점끼리의 거리 구하기. 이 때, vertex 배열을 유심히 보자. int bfs(int sy, int sx, int from, int to) { memset(visit, false, sizeof(visit)); memset(vertex, 0, sizeof(vertex)); visit[sy][sx] = true; queue<info> q; for (int i = 0; i < 4; i++) q.push({ sy, sx, i }); // 시작부터 4가지 방향을 고려해야한다. int ret = -1; while (!q.empty()) { int qs = q.size(); while (qs--) { int r = q.front().y; int c = q.front().x; int d = q.front().d; q.pop(); // to 정점에 도착했고, 아직 그 to정점에 대한 방향(d)의 값이 설정되지 않았다면(도착하지 않았다면) if (m[r][c] == to) if(!vertex[to][d]) vertex[to][d] = ret; int y = r + dy[d]; int x = c + dx[d]; if (y < 0 || y >= N || x < 0 || x >= M || visit[y][x]) continue; if (m[y][x] == 0 || m[y][x] == to) // 실수 주의 { visit[y][x] = true; q.push({ y, x, d }); } } ++ret; } for (int i = 0; i < 4; i++) if (vertex[to][i] >= 2) // 문제 조건 return vertex[to][i]; return INF; } int Find(int x) { if (parent[x] == x) return x; return parent[x] = Find(parent[x]); } void Union(int a, int b) { a = Find(a); b = Find(b); if (a < b) parent[b] = a; else parent[a] = b; } int main(void) { //cin.tie(0); scanf("%d %d", &N, &M); for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) scanf("%d", &m[i][j]); for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) if (!visit[i][j] && m[i][j]) { dfs(i, j, gc); ++gc; } --gc; for (int i = 1; i <= gc; i++) parent[i] = i; // v[정점] = {해당 정점의 좌표들} for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) if (m[i][j]) v[m[i][j]].push_back({ i, j }); for (int i = 1; i <= gc; i++) { for (int j = i + 1; j <= gc; j++) { int Min = INF; // 최솟값 bool calc = false; for (auto pos : v[i]) { int get = bfs(pos.first, pos.second, i, j); if (get >= 2 && get != INF) { calc = true; Min = min(Min, get); } } if (calc) mst.push_back({ Min, i, j }); } } // 간선의 가중치를 중심으로 오름차순(MST를 활용하기 위해) sort(mst.begin(), mst.end(), cmp); int cnt = 0; for (auto i : mst) if (Find(i.here) != Find(i.next)) { Union(i.here, i.next); answer += i.w; ++cnt; if (cnt == gc - 1) break; } // MST 특성상 간선의 개수는 전체 정점 - 1이 되어야 한다. printf("%d\n", cnt == gc - 1 ? answer : -1); return 0; } | cs |
728x90
반응형
'알고리즘 문제 > BOJ' 카테고리의 다른 글
1092번 배 (0) | 2019.09.28 |
---|---|
2887번 행성 터널 (0) | 2019.09.28 |
2842번 집배원 한상덕 (0) | 2019.09.26 |
2606번 바이러스 (0) | 2019.09.22 |
17471번 게리맨더링 (0) | 2019.09.21 |