【POJ1679】The Unique MST
1 //ver1: Kruskal+暴力枚举删除边 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 int t,n,m,first; 7 int a,ok,minx,p[101]; 8 struct edge{ 9 int v1,v2,d,v; //v标记MST中的每一条边 10 }e[10001]; 11 int findp(int x){ 12 return x==p[x]?x:p[x]=findp(p[x]); 13 } 14 int cmp(edge a,edge b){ 15 return a.d<b.d; 16 } 17 void init(){ 18 cin>>n>>m; 19 ok=1;first=1; 20 for(int i=0;i<m;i++){ 21 cin>>e[i].v1>>e[i].v2>>e[i].d; 22 e[i].v=0; 23 } 24 sort(e,e+m,cmp); 25 } 26 int Kruskal(){ 27 for(int i=1;i<=n;i++) 28 p[i]=i; 29 a=n; int sum=0; 30 for(int i=0;i<m;i++){ 31 int p1=findp(e[i].v1),p2=findp(e[i].v2); 32 if(p1!=p2){ 33 sum+=e[i].d; 34 a--; 35 p[p1]=p2; 36 if(first) e[i].v=1; //边i属于MST 37 } 38 if(a==1) break; 39 } 40 if(a==1) return sum; 41 return -1; 42 } 43 int main(){ 44 cin>>t; 45 while(t--){ 46 init(); 47 minx=Kruskal(); //求MST 48 first=0; //注意MST已经求过了 49 for(int i=0;i<m;i++){ 50 if(e[i].v){ //删除MST中的一条边,再添加一条边形成连通图 51 int t=e[i].v1; //把这条件的两个点变成一个点,从而在下面的Kruskal中不会再选择这条边 52 e[i].v1=e[i].v2; 53 int sum=Kruskal(); 54 if(sum==minx) {ok=0;break;} 55 e[i].v1=t; 56 } 57 } 58 if(ok) cout<<minx<<endl; 59 else cout<<"Not Unique!\n"; 60 } 61 } 62 //ver2:Kruskal+判断是否存在权值相等且连接的等价集合相同 63 #include<cstdio> 64 #include<iostream> 65 #include<algorithm> 66 using namespace std; 67 int t,n,m,a,minx,ok,p[101]; 68 struct edge{ 69 int x,y,w; 70 }e[10001]; 71 int cmp(edge a,edge b){ 72 return a.w<b.w; 73 } 74 int findp(int x){ 75 return x==p[x]?x:p[x]=findp(p[x]); 76 } 77 void init(){ 78 minx=0;ok=1; 79 scanf("%d%d",&n,&m); a=n; 80 for(int i=1;i<=n;i++) p[i]=i; 81 for(int i=0;i<m;i++) 82 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w); 83 sort(e,e+m,cmp); 84 } 85 void Kruskal(){ 86 for(int i=0;i<m;i++){ 87 int p1=findp(e[i].x),p2=findp(e[i].y); 88 if(p1!=p2){ 89 for(int j=i+1;j<m;j++) 90 if(e[i].w==e[j].w){ 91 //判断链接的是否是相同的集合 92 int p3=findp(e[j].x),p4=findp(e[j].y); 93 if(p3==p1&&p4==p2||p3==p2&&p4==p1){ 94 ok=0; 95 return; 96 } 97 } 98 else break;//由于e[]是有序的,发现权值不同,立即退出循环 99 p[p1]=p2; 100 minx+=e[i].w; 101 a--; 102 } 103 if(a==1) break; 104 } 105 } 106 int main() 107 { 108 scanf("%d",&t); 109 while(t--){ 110 init(); 111 Kruskal(); 112 if(ok) printf("%d\n",minx); 113 else printf("Not Unique!\n"); 114 } 115 } 116 //ver3: 可以前后求两次MST,在权值相同的情况下,第一次边编号小的优先选,第二次边编号大的优先选, 117 //判断两次MST是否相同即可(一是最短路径和是否相等,二是所有的边是否相同)
判断最小生成树是否唯一