www.acmicpc.net/problem/1626

 

1626번: 두 번째로 작은 스패닝 트리

첫째 줄에 그래프의 정점의 수 V(1 ≤ V ≤ 50,000)와 간선의 수 E(1 ≤ E ≤ 200,000)가 들어온다. 둘째 줄부터 E+1번째 줄까지 한 간선으로 연결된 두 정점과 그 간선의 가중치가 주어진다. 가중치는 100,

www.acmicpc.net

생애 첫 다이아문제 AC라 기분이 좋군요 ㅎㅎ

 

emoney96.tistory.com/193

 

boj 15481 그래프와 MST

www.acmicpc.net/problem/15481 15481번: 그래프와 MST 첫째 줄에 정점의 개수 N과 간선의 개수 M (2 ≤ N ≤ 200,000, N-1 ≤ M ≤ 200,000) 둘째 줄부터 M개의 줄에 간선의 정보 u, v, w가 주어진다. u와 v를..

emoney96.tistory.com

이 문제를 풀기 전에 그래프와 MST 문제를 풀어봐야합니다. (풀이가 비슷합니다.)

 

 

두 번째로 작은 스패닝 트리는 최소 스패닝 트리에서 하나의 간선만 바꿔주면 됩니다.

즉, 하나의 간선이 다릅니다.

 

1. 먼저 주어진 간선들로 첫 번째 mst를 구합니다.

2. 첫 번째 mst에 사용된 간선들로 인접 리스트를 만듭니다.

3. 인접 리스트의 depth를 구합니다.

4. 간선정보를 하나씩 가져와서 lca를 각각 구합니다.

5. mst - lca(u, v) + w의 최소를 구합니다.

 

여기까지는 그래프와 MST문제와 별다를게 없지만 이문제와의 차이점이 있습니다.

1. 두 번째 mst가 첫 번째 mst보다 커야함 -> 두 번째 mst를 구하지 못할 수 있음

2. 첫 번째 mst조차 구하지 못할 수 있음

 

위의 경우에는 -1을 출력해야합니다.

 

2번 경우를 확인할 때는 첫 번째 mst를 구할 때 고른 간선이 N - 1개인지 확인하는 것으로 예외처리 합니다.

1번 경우를 확인할 때는 lca로 u ~ v 경로의 간선을 구할 때

두개의 간선(가장 높은 가중치의 간선과 그 다음 높은 가중치의 간선)을 구합니다.

가장 높은 간선이 추가할 간선과 가중치가 같으면 1번조건에 걸리기 때문에 그 다음 높은 간선을 제거해야합니다.

 

마지막으로 ans가 최댓값이면 -1, 아니면 갱신된 값을 출력해줍니다.

 

정리하자면

1. 주어진 간선들로 첫 번째 mst를 구합니다.

2. 첫 번째 mst에 사용된 간선들로 인접 리스트를 만듭니다.

3. 인접 리스트의 depth를 구합니다.

4. lca(u, v)로 첫 번째, 두 번째 간선을 구합니다.

5. 구한 간선들이 w와 다를 경우에만 ans를 갱신합니다.

6. ans가 max값이면 -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
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define MAX 50000
#define LOG 20
using namespace std;
 
typedef struct edge {
    int u;
    int v;
    int w;
}edge;
 
vector<pair<intint> > list[MAX + 1];
vector<edge> v;
pair<intpair<intint> > lcaParent[MAX + 1][LOG];
int mstParent[MAX + 1], depth[MAX + 1];
bool visit[MAX + 1];
int mst;
int N, M, cnt;
 
bool cmp(edge a, edge b) {
    return a.w < b.w;
}
 
pair<intint> f(pair<intint> a, pair<intint> b) {
    vector<int> nv;
    nv.push_back(a.first);
    nv.push_back(a.second);
    nv.push_back(b.first);
    nv.push_back(b.second);
    sort(nv.rbegin(), nv.rend());
    nv.erase(unique(nv.begin(), nv.end()), nv.end());
    if (nv.size() < 2) nv.push_back(-1);
    return { nv[0], nv[1] };
}
 
void dfs(int v, int d) {
    depth[v] = d;
    visit[v] = true;
 
    for (int i = 0; i < list[v].size(); i++) {
        int next = list[v][i].first;
        int w = list[v][i].second;
 
        if (visit[next]) continue;
        lcaParent[next][0= { v,{w,-1} };
        dfs(next, d + 1);
    }
}
 
int find(int v) {
    if (mstParent[v] == v) return v;
    return mstParent[v] = find(mstParent[v]);
}
 
void Union(int x, int y, int w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    list[x].push_back({ y,w });
    list[y].push_back({ x,w });
    mstParent[b] = a;
    mst += w;
    cnt++;
}
 
void makeMst() {
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        int w = v[i].w;
 
        Union(x, y, w);
        if (cnt == N - 1break;
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        mstParent[i] = i;
    }
    memset(lcaParent, -1sizeof(lcaParent));
}
 
pair<intint> lca(int x, int y) {
    if (depth[x] > depth[y]) swap(x, y);
    pair<intint> ret = { -1,-1 };
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (depth[y] - depth[x] >= (1 << i)) {
            ret = f(ret, lcaParent[y][i].second);
            
            y = lcaParent[y][i].first;
        }
    }
 
    if (x == y) return ret;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (lcaParent[x][i].first == 0continue;
        if (lcaParent[x][i].first != lcaParent[y][i].first) {
            ret = f(ret, lcaParent[x][i].second);
            ret = f(ret, lcaParent[y][i].second);
 
            x = lcaParent[x][i].first;
            y = lcaParent[y][i].first;
        }
    }
 
    ret = f(ret, lcaParent[x][0].second);
    ret = f(ret, lcaParent[y][0].second);
    
    return ret;
}
 
void func() {
    if (cnt < N - 1) {
        cout << "-1\n";
        return;
    }
 
    dfs(11);
    for (int j = 1; j < LOG; j++) {
        for (int i = 1; i <= N; i++) {
            lcaParent[i][j].first = lcaParent[lcaParent[i][j - 1].first][j - 1].first;
            if (lcaParent[i][j].first == -1continue;
            lcaParent[i][j].second = f(lcaParent[i][j - 1].second, lcaParent[lcaParent[i][j - 1].first][j - 1].second);
        }
    }
 
    long long ans = 2147483647;
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        int w = v[i].w;
        pair<intint> sub = lca(x, y);
        
        if (sub.first != w && sub.first != -1) ans = min(ans, (long long)(mst - sub.first + w));
        else if (sub.second != w && sub.second != -1) ans = min(ans, (long long)(mst - sub.second + w));
    }
 
    if (ans >= 2147483647cout << "-1\n";
    else cout << ans << '\n';
}
 
void input() {
    int x, y;
    int w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> x >> y >> w;
        v.push_back({ x,y,w });
    }
    sort(v.begin(), v.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    makeMst();
    func();
 
    return 0;
}
cs

'algorithm > LCA' 카테고리의 다른 글

boj 6059 Pasture Walking  (0) 2021.06.16
boj 3584 가장 가까운 공통 조상  (0) 2021.06.16
boj 15481 그래프와 MST  (0) 2021.04.01
boj 15480 LCA와 쿼리  (0) 2021.02.14
boj 11438 LCA 2  (0) 2021.02.11

www.acmicpc.net/problem/15481

 

15481번: 그래프와 MST

첫째 줄에 정점의 개수 N과 간선의 개수 M (2 ≤ N ≤ 200,000, N-1 ≤ M ≤ 200,000) 둘째 줄부터 M개의 줄에 간선의 정보 u, v, w가 주어진다. u와 v를 연결하는 간선의 가중치가 w라는 뜻이다. (1 ≤ u, v ≤

www.acmicpc.net

M개의 간선 정보가 들어오는데 i번째 간선을 포함한 MST를 출력하는 문제입니다.

 

우선 전체 MST를 구해줍니다.

그 다음 i번째 간선을 포함해주고 그 간선에 연결된 정점들의 경로에 있는 MST 간선을 하나 제거해야합니다.

이 경로를 순회해야 하기때문에 이를 LCA로 구합니다.

 

여기서 LCA를 구하기 전에 각 정점의 높이를 구해야하는데 인접 리스트를 MST 간선들만 가지고 구해줍니다.

그럼 u v 경로의 최대 간선을 구할 수 있습니다.

 

답은 mst - lca(u, v) + w을 출력해주시면 되고, 입력이 들어온 순서대로 출력해야하니 인덱스를 유지해야합니다.

 

정리하자면

1. 먼저 주어진 간선들로 MST를 구합니다.

2. MST에 사용된 간선들로 인접 리스트를 만들어줍니다.

3. 인접리스트의 depth를 구합니다.

4. 입력(간선 정보)이 들어왔던 순서대로 lca를 구해줍니다.

5. mst - lca(u, v) + w을 출력합니다.

 

 

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
#include <iostream>
#include <vector>
#include <algorithm>
#define MAX 200000
#define LOG 20
using namespace std;
typedef long long ll;
 
typedef struct edge {
    int u;
    int v;
    ll w;
}edge;
 
vector<pair<int, ll> > list[MAX + 1];
vector<edge> v, nv;
pair<int, ll> lcaParent[MAX + 1][LOG];
int mstParent[MAX + 1], depth[MAX + 1];
bool visit[MAX + 1];
ll mst;
int N, M, cnt;
 
bool cmp(edge a, edge b) {
    return a.w < b.w;
}
 
void dfs(int v, int d) {
    depth[v] = d;
    visit[v] = true;
 
    for (int i = 0; i < list[v].size(); i++) {
        int next = list[v][i].first;
        ll w = list[v][i].second;
 
        if (visit[next]) continue;
        lcaParent[next][0= { v,w };
        dfs(next, d + 1);
    }
}
 
int find(int v) {
    if (mstParent[v] == v) return v;
    return mstParent[v] = find(mstParent[v]);
}
 
void Union(int x, int y, ll w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    list[x].push_back({ y,w });
    list[y].push_back({ x,w });
    mstParent[b] = a;
    mst += w;
    cnt++;
}
 
void makeMst() {
    for (int i = 0; i < M; i++) {
        int x = nv[i].u;
        int y = nv[i].v;
        ll w = nv[i].w;
 
        Union(x, y, w);
        if (cnt == N - 1break;
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        mstParent[i] = i;
    }
}
 
ll lca(int x, int y) {
    if (depth[x] > depth[y]) swap(x, y);
    ll ret = 0;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (depth[y] - depth[x] >= (1 << i)) {
            ret = max(ret, lcaParent[y][i].second);
            y = lcaParent[y][i].first;
        }
    }
 
    if (x == y) return ret;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (lcaParent[x][i].first == 0continue;
        if (lcaParent[x][i].first != lcaParent[y][i].first) {
            ret = max(ret, max(lcaParent[x][i].second, lcaParent[y][i].second));
 
            x = lcaParent[x][i].first;
            y = lcaParent[y][i].first;
        }
    }
 
    return max(ret, max(lcaParent[x][0].second, lcaParent[y][0].second));
}
 
void func() {
    dfs(11);
    for (int j = 1; j < LOG; j++) {
        for (int i = 1; i <= N; i++) {
            lcaParent[i][j].first = lcaParent[lcaParent[i][j - 1].first][j - 1].first;
            lcaParent[i][j].second = max(lcaParent[i][j - 1].second, lcaParent[lcaParent[i][j - 1].first][j - 1].second);
        }
    }
 
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        ll w = v[i].w;
        ll sub = lca(x, y);
        cout << mst - sub + w << '\n';
    }
}
 
void input() {
    int x, y;
    ll w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> x >> y >> w;
        v.push_back({ x,y,w });
    }
    nv = v;
    sort(nv.begin(), nv.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    makeMst();
    func();
 
    return 0;
}
cs

'algorithm > LCA' 카테고리의 다른 글

boj 3584 가장 가까운 공통 조상  (0) 2021.06.16
boj 1626 두 번째로 작은 스패닝 트리  (0) 2021.04.02
boj 15480 LCA와 쿼리  (0) 2021.02.14
boj 11438 LCA 2  (0) 2021.02.11
boj 11437 LCA  (0) 2021.02.11

www.acmicpc.net/problem/1647

 

1647번: 도시 분할 계획

첫째 줄에 집의 개수N, 길의 개수M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번 집

www.acmicpc.net

크루스칼 알고리즘과 프림 알고리즘 둘 다 사용 가능합니다.

 

MST에서 추가된 조건은 도시가 두 개로 분할된다는 점입니다.

노드의 갯수가 N인 그래프에서 MST는 N - 1개의 간선을 선택합니다.

크루스칼 알고리즘으로는 N - 2개의 간선을 선택해주면 도시는 두개로 분할되고,

프림 알고리즘으로는 한 정점을 기준으로 N - 1개의 간선을 골라주면서 그 중 max간선을 뺀 값이 답입니다.

 

 

[Kruskal]

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
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
 
typedef struct Point {
    int u;
    int v;
    int w;
};
 
vector<Point> list;
int parent[100001];
int N, M, ans, cnt;
 
bool cmp(Point a, Point b) {
    if (a.w < b.w) return true;
    else return false;
}
 
int find(int v) {
    if (parent[v] == v) return v;
    return parent[v] = find(parent[v]);
}
 
void Union(int x, int y, int w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    parent[b] = a;
    ans += w;
    cnt++;
}
 
void func() {
    for (int i = 0; i < M; i++) {
        int u = list[i].u;
        int v = list[i].v;
        int w = list[i].w;
 
        Union(u, v, w);
        if (cnt == N - 2break;
    }
 
    cout << ans << '\n';
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        parent[i] = i;
    }
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> u >> v >> w;
        list.push_back({ u, v, w });
    }
    init();
    sort(list.begin(), list.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

 

[Prim]

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
#include <iostream>
#include <vector>
#include <queue>
#define max(a, b) {a > b ? a : b}
using namespace std;
 
vector<pair<intint> > list[100001];
bool visit[100001];
int N, M, ans, cnt;
 
void func() {
    priority_queue<pair<intint> > q;
    int maxcost = 0;
    visit[1= true;
    for (int i = 0; i < list[1].size(); i++) {
        q.push({ -list[1][i].second, list[1][i].first });
    }
 
    while (!q.empty()) {
        int x = q.top().second;
        int w = -q.top().first;
        q.pop();
 
        if (visit[x]) continue;
        visit[x] = true;
        maxcost = max(maxcost, w);
        ans += w;
        cnt++;
        if (cnt == N - 1break;
 
        for (int i = 0; i < list[x].size(); i++) {
            int next = list[x][i].first;
            int nextw = list[x][i].second;
 
            q.push({ -nextw, next });
        }
    }
 
    cout << ans - maxcost << '\n';
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    while (M--) {
        cin >> u >> v >> w;
        list[u].push_back({ v,w });
        list[v].push_back({ u,w });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

'algorithm > MST' 카테고리의 다른 글

boj 1922 네트워크 연결  (0) 2021.03.19
boj 1197 최소 스패닝 트리  (0) 2021.03.18

www.acmicpc.net/problem/1922

 

1922번: 네트워크 연결

이 경우에 1-3, 2-3, 3-4, 4-5, 4-6을 연결하면 주어진 output이 나오게 된다.

www.acmicpc.net

emoney96.tistory.com/174

 

boj 1197 최소 스패닝 트리

www.acmicpc.net/problem/1197 1197번: 최소 스패닝 트리 첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정..

emoney96.tistory.com

위 문제와 같은 풀이방법입니다.

크루스칼과 프림 두 방법 모두 사용이 가능합니다.

 

 

[Kruskal]

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
typedef struct Point {
    int u;
    int v;
    int w;
};
 
vector<Point> list;
int parent[1001];
int N, M, ans, cnt;
 
bool cmp(Point a, Point b) {
    if (a.w < b.w) return true;
    else return false;
}
 
int find(int v) {
    if (parent[v] == v) return v;
    return parent[v] = find(parent[v]);
}
 
void Union(int x, int y, int w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    parent[b] = a;
    ans += w;
    cnt++;
}
 
void func() {
    for (int i = 0; i < M; i++) {
        int u = list[i].u;
        int v = list[i].v;
        int w = list[i].w;
 
        Union(u, v, w);
        if (cnt == N - 1break;
    }
 
    cout << ans << '\n';
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        parent[i] = i;
    }
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    init();
    for (int i = 0; i < M; i++) {
        cin >> u >> v >> w;
        list.push_back({ u,v,w });
    }
    sort(list.begin(), list.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

 

[Prim]

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
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
 
vector<pair<intint> > list[1001];
bool visit[1001];
int N, M, ans, cnt;
 
void func() {
    priority_queue<pair<intint> > q;
    visit[1= true;
    for (int i = 0; i < list[1].size(); i++) {
        q.push({ -list[1][i].second, list[1][i].first });
    }
 
    while (!q.empty()) {
        int x = q.top().second;
        int w = -q.top().first;
        q.pop();
 
        if (visit[x]) continue;
        visit[x] = true;
        ans += w;
        cnt++;
        if (cnt == N - 1break;
        for (int i = 0; i < list[x].size(); i++) {
            int next = list[x][i].first;
            int nextw = list[x][i].second;
 
            q.push({ -nextw, next });
        }
    }
 
    cout << ans << '\n';
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    while (M--) {
        cin >> u >> v >> w;
        list[u].push_back({ v,w });
        list[v].push_back({ u,w });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

'algorithm > MST' 카테고리의 다른 글

boj 1647 도시 분할 계획  (0) 2021.03.19
boj 1197 최소 스패닝 트리  (0) 2021.03.18

www.acmicpc.net/problem/1197

 

1197번: 최소 스패닝 트리

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이

www.acmicpc.net

최소 스패닝 트리(MST)의 기본 연습문제입니다.

크루스칼 알고리즘과 프림 알고리즘 둘 다 사용하였습니다.

 

크루스칼 알고리즘은 가중치가 낮은 순으로 간선을 골라주시면 되는데 사이클 방지를 위해 Union-find를 이용합니다.

뽑은 간선의 두 정점을 union-find로 이어주고 parent를 같게합니다.

그 다음에 뽑은 간선의 두 정점의 parent가 같으면 사이클이 발생하므로 제외시켜주는 방식입니다.

 

프림 알고리즘은 한 정점을 임의로 정하여 bfs와 비슷한 방식으로 순회하는데

방문한 정점에 연결된 간선 모두를 우선순위 큐에 넣고

다음 방문할 정점은 큐에 있는 정점 중 가중치가 가장 낮은 정점입니다.

만약 이미 방문하여 연결된 간선 모두를 큐에 넣었던 정점이면 continue를 해주고 방문하지 않은 정점에 연결된 간선만 모두 추가합니다.

 

두 방식 모두 N - 1개의 간선을 골랐으면 break를 하고 지금까지 더했던 가중치를 출력해줍니다.

 

 

[Kruskal]

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
typedef struct Point {
    int u;
    int v;
    int w;
};
 
vector<Point> list;
int parent[10001];
int N, M, ans, cnt;
 
bool cmp(Point a, Point b) {
    if (a.w < b.w) return true;
    else return false;
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        parent[i] = i;
    }
}
 
int find(int v) {
    if (parent[v] == v) return v;
    return parent[v] = find(parent[v]);
}
 
void Union(int x, int y, int w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    parent[b] = a;
    ans += w;
    cnt++;
}
 
void func() {
    for (int i = 0; i < M; i++) {
        int u = list[i].u;
        int v = list[i].v;
        int w = list[i].w;
 
        Union(u, v, w);
        if (cnt == N - 1break;
    }
 
    cout << ans << '\n';
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> u >> v >> w;
        list.push_back({ u,v,w });
    }
    sort(list.begin(), list.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    func();
 
    return 0;
}
cs

 

 

[Prim]

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
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
 
vector<pair<intint> > list[10001];
bool visit[10001];
int N, M, ans, cnt;
 
void func() {
    priority_queue<pair<intint> > q;
    for (int i = 0; i < list[1].size(); i++) {
        q.push({ -list[1][i].second, list[1][i].first });
    }
    visit[1= true;
    
    while (!q.empty()) {
        int x = q.top().second;
        int w = -q.top().first;
        q.pop();
 
        if (visit[x]) continue;
        visit[x] = true;
        ans += w;
        cnt++;
        if (cnt == N - 1break;
 
        for (int i = 0; i < list[x].size(); i++) {
            int next = list[x][i].first;
            int nextw = list[x][i].second;
 
            q.push({ -nextw, next });
        }
    }
 
    cout << ans << '\n';
}
 
void input() {
    int u, v, w;
    cin >> N >> M;
    while(M--) {
        cin >> u >> v >> w;
        list[u].push_back({ v, w });
        list[v].push_back({ u, w });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > MST' 카테고리의 다른 글

boj 1647 도시 분할 계획  (0) 2021.03.19
boj 1922 네트워크 연결  (0) 2021.03.19

+ Recent posts