题目大意:
给定一个无向图,寻找它的最小生成树,如果仅有一种最小生成树,输出所有边的和,否则输出unique!
根据kruscal原理来说,每次不断取尽可能小的边不断添加入最小生成树中,那么可知如果所有边的长度都不相同,那么kruscal取得过程必然只有一种情况,由小到大
所以要是存在多种情况的最小生成树,那么必然是存在相同的边
初始将所有相同的边进行标记,生成第一次最小生成树后,不断去除其中带标记的边,然后再计算最小生成树,判断能否得到同样的答案,如果可以,说明不止一种情况
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define N 105 6 int fa[N] , same[N] , first[N] , k; 7 int rec[N] , amo;//rec[]记录MST中含有相同长度边的位置,amo记录其数量 8 struct Edge{ 9 int x,y,d,next,flag; 10 bool same; 11 bool operator<(const Edge &m) const{ 12 return d<m.d; 13 } 14 }e[N*N]; 15 16 int find_head(int x) 17 { 18 while(fa[x]!=x) x=fa[x]; 19 return x; 20 } 21 22 bool Union(int x,int y) 23 { 24 int fa_x = find_head(x); 25 int fa_y = find_head(y); 26 fa[fa_x] = fa_y; 27 return fa_x == fa_y; 28 } 29 30 void add_edge(int x, int y , int d) 31 { 32 e[k].x=x , e[k].y=y , e[k].d=d , e[k].flag=1 , e[k].next=first[x]; 33 e[k].same = false; 34 first[x] = k++; 35 } 36 37 int cal_MST(int n , int flag) 38 { 39 int ans = 0 , cnt=0; 40 for(int i=1 ; i<=n ; i++) fa[i]=i; 41 for(int i=0 ; i<k ; i++){ 42 if(e[i].flag==1){ 43 if(!Union(e[i].x , e[i].y)){ 44 ans+=e[i].d; 45 if(e[i].same && flag){ 46 rec[amo++] = i; 47 } 48 cnt++; 49 if(cnt == n-1) break; 50 } 51 } 52 } 53 return ans; 54 } 55 56 int main() 57 { 58 int T; 59 scanf("%d" , &T); 60 while(T--) 61 { 62 int n , m , x , y , d; 63 scanf("%d%d" , &n , &m); 64 k=0; 65 memset(first , -1 , sizeof(first)); 66 for(int i=0 ; i<m ; i++){ 67 scanf("%d%d%d" , &x , &y , &d); 68 add_edge(x , y , d); 69 } 70 71 sort(e , e+k); 72 //对存在相同边的边进行标记 73 for(int i=1 ; i<k ; i++) 74 if(e[i].d == e[i-1].d) e[i].same=e[i-1].same=true; 75 amo = 0; 76 int ans = cal_MST(n , 1); 77 bool is_unique = true; 78 for(int i=0 ; i<amo ; i++){ 79 e[rec[i]].flag = 0; 80 int t=cal_MST(n , 0); 81 if(t == ans){ 82 is_unique=false; 83 break; 84 } 85 e[rec[i]].flag = 1; 86 } 87 if(is_unique) printf("%d\n" , ans); 88 else puts("Not Unique!"); 89 } 90 return 0; 91 }
原文:http://www.cnblogs.com/CSU3901130321/p/4361988.html