BOJ

백준 1197 - 최소 스패닝 트리

yanJuicy 2019. 12. 26. 18:12
반응형

문제

 

https://www.acmicpc.net/problem/1197

 

1197번: 최소 스패닝 트리

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이 가중치 C인 간선으로 연결되어 있다는 의미이다. C는 음수일 수도 있으며, 절댓값이 1,000,000을 넘지 않는다. 최소 스패닝 트리의 가중치가 -2147483648보다 크거나 같고, 2147483647보다 작거나 같은 데

www.acmicpc.net

 

 

풀이

 

최소 스패닝 트리를 구하는 알고리즘은 크루스칼과 프림 알고리즘이 있다. 

 

1. 프림 알고리즘은 정점 집합을 기준으로 트리를 확장을 한다. 현재 정점을 기준으로 연결된 정점 중에서 가중치가 제일 작은 간선으로 연결된 정점을 추가해야 되는데, 이 때 우선순위 큐를 이용해서 정점을 추가한다. 우선순위 큐에 가중치를 기준으로 정점들을 저장하면 가중치가 제일 작은 다음 정점을 쉽게 알아낼 수 있다. 이 과정을 모든 정점을 방문할 때까지 반복하면 된다. 모든 정점을 방문하면 최소 스패닝 트리가 만들어지게 된다. 

 

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
#include <iostream>
#include <queue>
#include <vector>
 
using namespace std;
 
int V, E;
bool visit[10001];
vector<pair<int,int>> graph[10001];
priority_queue<pair<int,int>vector<pair<int,int>>, greater<pair<int,int>>> pq;
int result;
 
void prim(pair<intint> s)
{
    pq.push(s);
 
    while (!pq.empty())
    {
        pair<intint> curValue = pq.top();
        pq.pop();
 
        int curNode = curValue.second;
        if (visit[curNode]) continue;
 
        visit[curNode] = true;
        result += curValue.first;
 
        for (int j=0; j<graph[curNode].size(); j++)
            if (!visit[graph[curNode][j].second]) pq.push(graph[curNode][j]);
    }
}
 
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);
 
    cin >> V >> E;
 
    int from, to, weight;
    for (int i=0; i<E; i++)
    {
        cin >> from >> to >> weight;
        graph[from].push_back({weight, to});
        graph[to].push_back({weight, from});
    }
 
    prim({01});
 
    cout << result;
    return 0;
}
cs
 
 
 

 

 

크루스칼 알고리즘

 

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
#include <iostream>
#include <algorithm>
#include <vector>
 
using namespace std;
 
struct Edge
{
    int u, v, w;
 
    bool operator<(struct Edge & cmp)
    {
        return w < cmp.w;
    }
};
 
int V, E;
vector<Edge> graph;
int result;
int parent[10001], size[10001];
 
int findParent(int v)
{
    if (v == parent[v]) return v;
    return parent[v] = findParent(parent[v]);
}
 
void unionVertex(int u, int v)
{
    int p1 = findParent(u);
    int p2 = findParent(v);
 
    if (p1 != p2)
    {
        if (size[p1] < size[p2]) swap(p1, p2);
 
        parent[p2] = p1;
        size[p1] += size[p2];
        size[p2] = 0;
    }
}
 
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);
 
    cin >> V >> E;
 
    Edge e;
    for (int i=0; i<E; i++)
    {
        cin >> e.u >> e.v >> e.w;
        graph.push_back(e); 
    }
 
    sort(graph.begin(), graph.end());
 
    for (int i=1; i<=V; i++) parent[i] = i;
    
    for (int i=0; i<E; i++)
    {
        e = graph[i];
 
        if (findParent(e.u) != findParent(e.v))
        {
            unionVertex(e.u, e.v);
            result += e.w;
        }
    }
 
    cout << result;
 
    return 0;
}
cs

 

반응형

'BOJ' 카테고리의 다른 글

백준 2346 - 풍선 터뜨리기  (0) 2020.01.25
백준 1753 - 최단경로  (1) 2020.01.10
백준 1167 - 트리의 지름  (0) 2019.11.15
백준 1744 - 수 묶기  (0) 2019.10.09
백준 1697 - 숨바꼭질  (0) 2019.10.02