这里统一采用复杂度最优的Kruskal+最优性剪枝方法,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
/*Kruskal算法思路:先把边从小到大排序,然后从小到大选边,选边后将这两个点在并查集中merge一下,然后如果选边之前这两个点已经联通了(find相同)我们就跳过此次选边(因为选择这个边是没有意义的)*/
#include <bits/stdc++.h>
using namespace std;
//Kruskal
//记得输出不连通的情况(orz)
int f[101010];
struct node{
int x,y,z;
}a[1010101];
int n,m,ans = 0,cnt,tot;
int find(int x){
if(f[x] != x) return f[x] = find(f[x]);
return x;
}
bool cmp(node xx,node yy){
return xx.z < yy.z;
}
int main(){
cin>>n>>m;
for(int i = 1;i <= m;i++){
++cnt;
cin>>a[cnt].x>>a[cnt].y>>a[cnt].z;
}
sort(a+1,a+cnt+1,cmp);
for(int i = 1;i <= n;i++){
f[i] = i;
}
for(int i = 1;i <= cnt;i++){
if(find(a[i].x) != find(a[i].y)){
ans += a[i].z;
tot++;
f[find(a[i].x)] = f[find(a[i].y)];
}
if(tot == n-1){
cout<<ans<<endl;
return 0;
}
}
puts("impossible");
}

【一本通提高篇最小生成树】北极通信网络

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 <bits/stdc++.h>
using namespace std;
//Kruskal
int f[1010100];
struct node {
int x, y;
} a[1010101];
struct edge {
int x, y;
double z;
} e[1010101];
int n, m, cnt, tot;
double ans;
int find(int x) {
if (f[x] != x) return f[x] = find(f[x]);
return x;
}
bool cmp(edge xx, edge yy) {
return xx.z < yy.z;
}
double calc(int i, int j) {
return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) *
(a[i].y - a[j].y));
}
int main() {
int t;
cin >> t;
while (t--) {
scanf("%d%d",&n,&m);
tot = 0,ans = 0,cnt = 0;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
}
for (int i = 1; i <= m; i++) {
for (int j = i+1; j <= m; j++) {
e[++cnt] = {i, j, calc(i, j)};
}
}
sort(e + 1, e + cnt + 1, cmp);
for (int i = 1; i <= m; i++) {
f[i] = i;
}
for (int i = 1; i <= cnt; i++) {
if (find(e[i].x) != find(e[i].y)) {
ans += e[i].z;
tot++;
f[find(e[i].x)] = f[find(e[i].y)];
}
if (tot == m - n) {
printf("%.2lf\n",e[i].z);
goto endd;
}
}
endd:
;
}
}

【一本通提高篇最小生成树】新的开始

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
/*超级源点思路:每个点i都和编号为0的点连一个边权为v[i]的边*/
#include <bits/stdc++.h>
using namespace std;

struct node {
int fr, to, l;
} e[101000];
int tot, ans;
int n;
int f[101000];
int cnt;
int v[100000];
bool cmp(node xx, node yy) {
return xx.l < yy.l;
}
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
void merge(int x, int y) {
f[find(x)] = f[find(y)];
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
e[++cnt] = {i, 0, v[i]};
}
for (int i = 1; i <= n; i++) f[i] = i;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int cost;
cin >> cost;
e[++cnt] = {i, j, cost};
}
}
sort(e + 1, e + 1 + cnt, cmp);
for (int i = 1; i <= cnt; i++) {
if (find(e[i].fr) != find(e[i].to)) {
merge(e[i].fr, e[i].to);
tot++;
ans += e[i].l;
}
if (tot == n) break;//n-1个点,然后还需要再建一个发电站
}
cout << ans << endl;
}