31102:Kruskal 最小生成树
题目
给定无向带权图,求最小生成树总权重;图不连通或权重累加溢出时失败。
解析
Kruskal 按边权非递减排序,每次用并查集判断两个端点是否已经连通。若不连通就加入这条边并合并集合;若已经连通,加入它会产生环。处理完后必须恰好选出 vertex_count - 1 条边。
答案
c
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
size_t left;
size_t right;
uint64_t weight;
} UndirectedEdge;
static int compare_edges(const void *left, const void *right) {
const UndirectedEdge *a = left;
const UndirectedEdge *b = right;
if (a->weight < b->weight) {
return -1;
}
if (a->weight > b->weight) {
return 1;
}
return 0;
}
static size_t dsu_find(size_t *parent, size_t element) {
size_t root = element;
while (parent[root] != root) {
root = parent[root];
}
while (parent[element] != element) {
size_t next = parent[element];
parent[element] = root;
element = next;
}
return root;
}
bool minimum_spanning_tree_weight(
size_t vertex_count,
const UndirectedEdge *edges,
size_t edge_count,
uint64_t *out_weight
) {
if (out_weight == NULL ||
(edge_count > 0 && edges == NULL)) {
return false;
}
if (vertex_count == 0) {
*out_weight = 0;
return true;
}
if (vertex_count > SIZE_MAX / sizeof(size_t) ||
edge_count > SIZE_MAX / sizeof(UndirectedEdge)) {
return false;
}
for (size_t i = 0; i < edge_count; ++i) {
if (edges[i].left >= vertex_count ||
edges[i].right >= vertex_count) {
return false;
}
}
size_t *parent = malloc(vertex_count * sizeof *parent);
size_t *sizes = malloc(vertex_count * sizeof *sizes);
UndirectedEdge *copy = edge_count == 0
? NULL
: malloc(edge_count * sizeof *copy);
if (parent == NULL || sizes == NULL ||
(edge_count > 0 && copy == NULL)) {
free(parent);
free(sizes);
free(copy);
return false;
}
for (size_t i = 0; i < vertex_count; ++i) {
parent[i] = i;
sizes[i] = 1;
}
if (edge_count > 0) {
for (size_t i = 0; i < edge_count; ++i) {
copy[i] = edges[i];
}
qsort(copy, edge_count, sizeof *copy, compare_edges);
}
size_t selected = 0;
uint64_t total = 0;
for (size_t i = 0;
i < edge_count && selected < vertex_count - 1;
++i) {
size_t left = dsu_find(parent, copy[i].left);
size_t right = dsu_find(parent, copy[i].right);
if (left == right) {
continue;
}
if (sizes[left] < sizes[right]) {
size_t temporary = left;
left = right;
right = temporary;
}
if (total > UINT64_MAX - copy[i].weight) {
free(parent);
free(sizes);
free(copy);
return false;
}
total += copy[i].weight;
parent[right] = left;
sizes[left] += sizes[right];
++selected;
}
bool connected = selected == vertex_count - 1;
if (connected) {
*out_weight = total;
}
free(parent);
free(sizes);
free(copy);
return connected;
}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
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
排序为