我们知道在构造最小生成树的时候有可能会选择不同的边,这样构造的最小生成树不相同,但是最小生成树的权是唯一的!
毫无疑问,无向图中存在相同权值的边是最小生成树不唯一的必要条件(但不是充分条件)。正因为如此,如果无向图中各边的权值都不相同,那么在用Kruskal算法构造最小生成树时,选择的方案是唯一的。
这里给出判定最小生成树唯一的算法思路:
1.对图中的每一条边,扫描其他边,如果存在相同权值的边,则对此边做标记。
2.然后使用Kruskal(或者prim)算法求出最小生成树。
3.如果这时候的最小生成树没有包含未被标记的边,即可判定最小生成树唯一。如果包含了标记的边,那么依次去掉这些边,再求最小生成树,如果求得的最小生成树的权值和原来的最小生成树的权值相同,即可判断最小生成树不唯一。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=11000; 7 const int M=15005; 8 int n,m,cnt; 9 int parent[N]; 10 int flag; 11 struct edge 12 { 13 int u; 14 int v; 15 int w; 16 int equals;///是否存在与该边权值相同的其他边 17 int used;///在第一次求得的MST中是否包含改变 18 int del;///边是否删除的标志 19 } edg[N]; 20 int cmp(edge x,edge y) 21 { 22 return x.w<y.w; 23 } 24 void init() 25 { 26 int i; 27 for(i=0; i<=N; i++) 28 { 29 parent[i]=i; 30 } 31 } 32 int Find(int x) 33 { 34 if(parent[x] != x) 35 { 36 parent[x] = Find(parent[x]); 37 } 38 return parent[x]; 39 }//查找并返回节点x所属集合的根节点 40 void Union(int x,int y) 41 { 42 x = Find(x); 43 y = Find(y); 44 if(x == y) 45 { 46 return; 47 } 48 parent[y] = x; 49 }//将两个不同集合的元素进行合并 50 int Kruskal() 51 { 52 init(); 53 int sum=0; 54 int num=0; 55 for(int i=0; i<m; i++) 56 { 57 if(edg[i].del==1) 58 { 59 continue; 60 } 61 int u=edg[i].u; 62 int v=edg[i].v; 63 int w=edg[i].w; 64 if(Find(u)!=Find(v)) 65 { 66 sum+=w; 67 if(!flag) 68 { 69 edg[i].used=1; 70 } 71 num++; 72 Union(u,v); 73 } 74 if(num>=n-1) 75 { 76 break; 77 } 78 } 79 return sum; 80 } 81 int main() 82 { 83 int t,d; 84 int i,j; 85 int counts1,counts2; 86 int flag2; 87 scanf("%d",&t); 88 while(t--) 89 { 90 counts1=0; 91 scanf("%d%d",&n,&m); 92 for(i=0; i<m; i++) 93 { 94 scanf("%d%d%d",&edg[i].u,&edg[i].v,&edg[i].w); 95 edg[i].del=0; 96 edg[i].used=0; 97 edg[i].equals=0;//一开始这个地方eq没有初始化,WA了好几发,操 98 } 99 for(i=0; i<m; i++) 100 { 101 for(j=0; j<m; j++) 102 { 103 if(i==j) 104 { 105 continue; 106 } 107 if(edg[i].w==edg[j].w) 108 { 109 edg[i].equals=1; 110 } 111 } 112 } 113 sort(edg,edg+m,cmp); 114 flag=0; 115 counts1=Kruskal(); 116 flag=1; 117 flag2=0; 118 for(i=0; i<m; i++) 119 { 120 if(edg[i].used&&edg[i].equals) 121 { 122 edg[i].del=1; 123 counts2=Kruskal();//printf("%d %d\n",i,s); 124 if(counts2==counts1) 125 { 126 flag2=1; 127 printf("Not Unique!\n"); 128 break; 129 } 130 edg[i].del=0; 131 } 132 } 133 if(!flag2) 134 { 135 printf("%d\n",counts1); 136 } 137 } 138 return 0; 139 }