문제링크
1647번: 도시 분할 계획
첫째 줄에 집의 개수N, 길의 개수M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번 집
www.acmicpc.net
문제난이도(solved.ac 기준)
Gold4
문제풀이
※문제의 말이 복잡해 보일 수 있지만, 결국 최소신장트리를 구하라는 말이다※
최소신장트리를 구하기 위해 Kruskal알고리즘을 이용해서 풀었다
1. 최초 각 노드들의 부모는 자기자신이다
- 아직 연결된 노드가 없으므로 자기자신이 부모가 된다
2. 간선 클래스를 이용하여 각 노드들의 간선 정보를 입력해준다
3. 간선비용을 기준으로 오름차순 정렬을 해준다
4. 간선정보를 순회하며 연결된 간선정보를 확인한다
4-1. 부모가 같은 경우는 간선비용을 계산하지 않는다
- 부모가 같은 경우는 사이클이 발생한 경우로 이미 방문한 노드를 한번 더 가게 된다
따라서 최소비용을 구한다는 것에 어긋나므로 계산하지 않는다
4-2. 부모가 다른 경우, 더 작은 노드의 값으로 부모를 합쳐주고 간선비용을 누적합 해준다
5. 마을을 2개로 나눈다
- 마을을 두개로 나눈 뒤에도 거리 유지비용이 최소가 되도록 해야한다
- 가장 마지막에 연결된 노드의 거리 유지비용이 가장 큰 비용이므로 마지막에 연결된 노드를 끊어준다
(2번에서 간선비용을 기준으로 오름차순 정렬했으므로 마지막에 연결된 간선이 가장 큰 비용을 갖게됨을 알수 있다)
자세한 풀이는 소스코드를 통해 확인해보자
소스코드
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
|
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N, M;
vector<int> parent;
//간선 클래스
class Edge {
public:
int node[2];
int distance;
Edge(int a, int b, int distance) {
this->node[0] = a;
this->node[1] = b;
this->distance = distance;
}
bool operator <(Edge& edge) {
return this->distance < edge.distance;
}
};
//부모노드 구하기
int getParent(int x) {
if (parent[x] == x) {
return x;
}
return parent[x] = getParent(parent[x]);
}
//부모노드 찾기
bool findParent(int a, int b) {
a = getParent(a);
b = getParent(b);
if (a == b) { //두 노드의 부모가 같은 경우
return true;
}
return false;
}
//두 노드의 부모 합치기
void unionParent(int a, int b) {
a = getParent(a);
b = getParent(b);
//구한 부모노드 중 더 작은 값으로 합친다
if (a < b) {
parent[b] = a;
}
else {
parent[a] = b;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
vector<Edge> vc;
cin >> N >> M;
parent.resize(N + 1, 0);
for (int i = 1; i <= N; i++) {
parent[i] = i; //현쟁 연결된 노드가 없으므로 자기자신이 부모
}
int n1, n2, dist;
for (int i = 0; i < M; i++) {
cin >> n1 >> n2 >> dist;
vc.push_back(Edge(n1, n2, dist)); //간선정보 입력(노드1, 노드2, 비용)
}
//간선 비용을 기준으로 오름차순 정렬
sort(vc.begin(), vc.end());
int sum = 0;
int prev = 0;
for (int i = 0; i < vc.size(); i++) {
//부모가 다른 경우(사이클이 발생하지 않는 경우)
if (!findParent(vc[i].node[0], vc[i].node[1])) {
sum += vc[i].distance;
prev = vc[i].distance; //가장 마지막에 연결된 간선 비용이 가장 큰 비용이다
unionParent(vc[i].node[0], vc[i].node[1]);
}
}
//가장 큰 비용으로 연결된 거리를 끊어 마을을 두개로 분리
//최소비용으로 두개의 마을을 관리할 수 있다
cout << sum-prev << '\n';
return 0;
}
|
cs |
'알고리즘 문제풀이' 카테고리의 다른 글
[프로그래머스 17680] 캐시 (0) | 2022.01.10 |
---|---|
[백준 9935]문자열 폭발 (0) | 2020.11.13 |
[프로그래머스 42884]단속카메라 (0) | 2020.11.06 |
[프로그래머스 42861]섬 연결하기 (0) | 2020.11.05 |
[프로그래머스 42885]구명보트 (0) | 2020.11.04 |