最小生成树
最小生成树(练习总结)
一.首先是其版子
#include<bits/stdc++.h> using namespace std; struct woyaohongming{ //不要在意这个结构体的名字......它只是用来存储图的而已 int s,e,w; //s-start,e-end,代表边上的两个节点,w就是权值费用了 }a[200005]; int f[200005]; //并查集用的f数组 bool cmp(woyaohongming a,woyaohongming b){ //sort排序规则,按费用从低到高排序 return a.w<b.w; } int find(int a){ //并查集的“找祖宗”函数,注意别忘路径压缩 if(f[a]==a) return a; else return f[a]=find(f[a]); } int main(){ int n,m,k; cin>>n>>m>>k; //输入n、m、k,没啥好讲的 for(int i=1;i<=n;i++) f[i]=i; //并查集数组初始化,每个节点的祖宗一开始是它自己 for(int i=1;i<=m;i++) cin>>a[i].s>>a[i].e>>a[i].w; //输入图的信息 sort(a+1,a+1+m,cmp); //快活的按权值排个序 int cnt=0,sum=0; //cnt是已经选中的边数,sum是最终要输出的最小权值 for(int i=1;i<=m;i++){ //m条边,循环m次 if(find(a[i].s)!=find(a[i].e)){ //如果俩节点的祖宗不相等(也就是不是回路),就可以加进去 f[find(a[i].s)]=find(a[i].e); //把它俩合并成一个祖宗 sum+=a[i].w; //更新最小费用 cnt++; //边数+1 } if(cnt>=n-k) //边数到达(n-k)条边,任务完成,break break; } if(cnt>=n-k) //如果选了n-k条边,可以搞最小生成树 cout<<sum; //输出最小权值 else cout<<"No Answer"; //要不然选了m条边还都搞不好,不能构成最小生成树 return 0; }
二.再来一点变形简单题
1.有指定范围的树生成
此题目与版子的区别就是需要多加一步判断,在kruskal的同时判断开始节点和结束节点是否已经在同一颗树内。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int f[30005],n,m,s,t; 4 struct edge{ 5 int u,v,w; 6 }e[30005]; 7 bool cmp(edge x,edge y){ 8 return x.w <y.w ; 9 } 10 int find(int x){ 11 if(f[x]==x)return x; 12 else return f[x]=find(f[x]); 13 } 14 void kruskal(){ 15 sort(e+1,e+m+1,cmp); 16 for(int i=1;i<=m;i++){ 17 int u=find(e[i].u ) ,v=find(e[i].v ); 18 f[u]=v; 19 if(find(s)==find(t)){//判断是否有公共祖先,如果有就证明此时为最小拥堵值 20 cout<<e[i].w; 21 return ; 22 } 23 } 24 } 25 int main(){ 26 cin>>n>>m>>s>>t; 27 for(int i=1;i<=n;i++)f[i]=i; 28 for(int i=1;i<=m;i++){ 29 cin>>e[i].u >>e[i].v >>e[i].w ; 30 } 31 kruskal(); 32 return 0; 33 }
2.指定生成树节点的个数
P1195 口袋的天空 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
想要 k 个点,并且联通,所以至少需要 k-1 条边。所以此生成器的结束条件为 cnt 是否达到 n-k 个。
1 #include<bits/stdc++.h> 2 //要想要k个点,就必须达到k-1条边 3 using namespace std; 4 int n,m,k,num,cnt; 5 int f[100005]; 6 struct edge{ 7 int u,v,w; 8 }e[10005]; 9 bool cmp(edge x,edge y){ 10 return x.w <y.w ; 11 } 12 int find(int x){ 13 if(f[x]==x)return x; 14 else return f[x]=find(f[x]); 15 } 16 void kruskal(){ 17 sort(e+1,e+m+1,cmp); 18 for(int i=1;i<=m;i++){ 19 int u=find(e[i].u ) ,v=find(e[i].v ); 20 if(u==v)continue; 21 f[u]=v; 22 cnt++; 23 num+=e[i].w ; 24 if(cnt>=n-k){ 25 cout<<num;return ;//注意此时正向判断时cnt的判断“是”放在 大括号内 26 }// 27 }// 28 cout<<"No Answer";return ;//“否”放在大括号外 29 } 30 int main(){ 31 cin>>n>>m>>k; 32 for(int i=1;i<=m;i++){ 33 cin>>e[i].u >>e[i].v >>e[i].w ; 34 } 35 for(int i=1;i<=n;i++)f[i]=i; 36 kruskal(); 37 38 return 0; 39 }
3.易错点(是否为公共祖先的正负向判断)
结果为“是”时,if正向判断在内,负向在外。
结果为“否”时,全部在内。
P2330 [SCOI2005] 繁忙的都市 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int f[30005],n,m,s,t,num,cnt; 4 struct edge{ 5 int u,v,w; 6 }e[30005]; 7 bool cmp(edge x,edge y){ 8 return x.w <y.w ; 9 } 10 int find(int x){ 11 if(f[x]==x)return x; 12 else return f[x]=find(f[x]); 13 } 14 void kruskal(){ 15 sort(e+1,e+m+1,cmp); 16 for(int i=1;i<=m;i++){ 17 if(find(e[i].u )!=find(e[i].v )){ 18 int u=find(e[i].u ) ,v=find(e[i].v ); 19 f[u]=v;cnt++;num=e[i].w ; 20 } 21 if(cnt==n-1)break; 22 } 23 } 24 int main(){ 25 cin>>n>>m; 26 for(int i=1;i<=n;i++)f[i]=i; 27 for(int i=1;i<=m;i++){ 28 cin>>e[i].u >>e[i].v >>e[i].w ; 29 } 30 kruskal(); 31 cout<<n-1<<" "<<num; 32 return 0; 33 }
P1547 [USACO05MAR] Out of Hay S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int f[30005],n,m,s,t,num,cnt; 4 struct edge{ 5 int u,v,w; 6 }e[30005]; 7 bool cmp(edge x,edge y){ 8 return x.w <y.w ; 9 } 10 int find(int x){ 11 if(f[x]==x)return x; 12 else return f[x]=find(f[x]); 13 } 14 void kruskal(){ 15 sort(e+1,e+m+1,cmp); 16 for(int i=1;i<=m;i++){ 17 if(find(e[i].u )==find(e[i].v ))continue; 18 int u=find(e[i].u ),v=find(e[i].v ); 19 f[u]=v; 20 cnt++; 21 num=e[i].w ; 22 23 if(cnt==n-1)break; 24 } 25 } 26 int main(){ 27 cin>>n>>m; 28 for(int i=1;i<=n;i++)f[i]=i; 29 for(int i=1;i<=m;i++){ 30 cin>>e[i].u >>e[i].v >>e[i].w ; 31 } 32 kruskal(); 33 cout<<num; 34 return 0; 35 }
本文来自博客园,作者:{追屿},转载请注明原文链接:https://www.cnblogs.com/happy-yu/p/18015857

浙公网安备 33010602011771号