poj 1679 判断最小生成树是否唯一(kruskal)

本文介绍了一种判断最小生成树(MST)是否唯一的算法思路,通过标记权重相同的边并利用Kruskal算法来实现。具体步骤包括扫描图中所有边以标记权重相同的边,使用Kruskal算法求取MST,最后通过去除这些标记边再次求取MST来判断MST的唯一性。
摘要由CSDN通过智能技术生成

判断最下生成树是否唯一的思路:

1、对图中的每一条边,扫描其他边,如果存在相同权值的边,则对该边做标记。

2、然后用Kruskal算法或Prim算法求MST。

3、求得MST后,如果该MST中未包含做了标记的边,即可判断MST唯一;如果包含做了标记的边,则依次去掉这些边再求MST,如果求得的MST权值和原来的MST的权值一样,即可判断MST不唯一。

针对poj 1679这题,采用Kruskal算法求MST,并判断MST是否唯一:

代码如下:

View Code
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 const int N=110;
  5 using namespace std;
  6 
  7 struct Edge{
  8     int u,v,w;  //边的顶点、权值
  9     bool operator < (const Edge &p) const {
 10         return w<p.w;
 11     }
 12     int equal; //标记,1表示存在权值相同的边,0表示不存在
 13     int used;//在第一次求得的MST中,是否包含该边
 14     int del;  //1删除,0未删除
 15 }edge[N*N];
 16 
 17 int n,m;
 18 bool first;
 19 int parent[N];
 20 
 21 //初始化
 22 void UFset(){
 23     for(int i=0;i<n;i++){
 24         parent[i]=-1;
 25     }
 26 }
 27 
 28 int Find(int x){
 29     int s;
 30     for(s=x;parent[s]>=0;s=parent[s]);
 31     //压缩路径,优化
 32     while(s!=x){
 33         int temp=parent[x];
 34         parent[x]=s;
 35         x=temp;
 36     }
 37     return s;
 38 }
 39 
 40 //合并
 41 void Union(int R1,int R2){
 42     int r1=Find(R1);
 43     int r2=Find(R2);
 44     int temp=parent[r1]+parent[r2];
 45     if(parent[r1]>parent[r2]){
 46         parent[r1]=r2;
 47         parent[r2]=temp;
 48     }else {
 49         parent[r1]=temp;
 50         parent[r2]=r1;
 51     }
 52 }
 53 
 54 int kruskal(){
 55     int sumweight=0,num=0;
 56     int u,v;
 57     UFset();
 58     for(int i=0;i<m;i++){
 59         if(edge[i].del==1)continue;//忽略去掉的边
 60         u=edge[i].u,v=edge[i].v;
 61         if(Find(u)!=Find(v)){
 62             sumweight+=edge[i].w;
 63             num++;
 64             Union(u,v);
 65             if(first)edge[i].used=1;
 66         }
 67         if(num>=n-1)break;
 68     }
 69     return sumweight;
 70 }
 71 
 72 int main(){
 73     int u,v,w,t;
 74     scanf("%d",&t);
 75     while(t--){
 76         scanf("%d%d",&n,&m);
 77         for(int i=0;i<m;i++){
 78             scanf("%d%d%d",&u,&v,&w);
 79             edge[i].u=u-1,edge[i].v=v-1,edge[i].w=w;
 80             edge[i].equal=0,edge[i].used=0,edge[i].del=0;
 81         }
 82         // 标记权值相同的边
 83         for(int i=0;i<m;i++){
 84             for(int j=0;j<m;j++){
 85                 if(i==j)continue;
 86                 if(edge[j].w==edge[i].w){
 87                     edge[i].equal=1;
 88                 }
 89             }
 90         }
 91         sort(edge,edge+m);
 92         first=true;
 93         int weight1=kruskal(),weight2;//第一次求MST
 94         first=false;
 95         int tag=1;
 96         for(int i=0;i<m;i++){
 97             if(edge[i].used&&edge[i].equal){
 98                 edge[i].del=1;
 99                 weight2=kruskal();
100                 if(weight1==weight2){
101                     printf("Not Unique!\n");
102                     tag=0;
103                     break;
104                 }
105                 edge[i].del=0;
106             }
107         }
108         if(tag)
109             printf("%d\n",weight1);
110     }
111     return 0;
112 }

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值