题目描述
判定最小生成树是否唯一...
分析
根据Kruskal算法构造最小生成树的思路,我们可知出现不唯一生成树的条件即为有权值相同的边,所以在求出最小生成树后,我们可以删除其中一条有相同权值的边,再次构造生成树,如果此时生成树的权值和原来的相同,那么生成树就不唯一.
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define N 10010 using namespace std; struct Edge{ int u,v,len; bool same,del,used;//是否有相同权值的边,是否被删除,此边是否被使用 }edge[N]; bool f; bool cmp(Edge a ,Edge b){ return a.len<b.len; } int root[N],rank[N],n,m,t; int find(int x){ return x==root[x]?root[x]:root[x]=find(root[x]); } int Union(int x,int y){ int xx=find(x),yy=find(y); if(xx!=yy){ if(rank[xx]>rank[yy]){ root[yy]=xx; rank[xx]+=rank[yy]; } else{ root[xx]=yy; rank[yy]+=rank[xx]; } return 1; } return 0; } int Kruskal(int n,int m){ int ans=0; for(int i=1;i<=n;i++){ root[i]=i; rank[i]=0; } for(int i=0;i<m;i++){ if(edge[i].del)continue; int rootu=find(edge[i].u); int rootv=find(edge[i].v); if(Union(rootu,rootv)){ ans+=edge[i].len; if(f) edge[i].used=1; } } return ans; } int main(){ cin>>t; while(t--){ cin>>n>>m; for(int i=0;i<m;i++){ cin>>edge[i].u>>edge[i].v>>edge[i].len; edge[i].same=edge[i].used=edge[i].del=0; } for(int i=0;i<m-1;i++) for(int j=i+1;j<m;j++) if(edge[i].len==edge[j].len){ edge[i].same=edge[j].same=1; } sort(edge,edge+m,cmp); f=1; int ans=Kruskal(n,m); f=0; int i; for(i=0;i<m;i++){ if(edge[i].used&&edge[i].same){ edge[i].del=1; int ans2=Kruskal(n,m); if(ans==ans2){ cout<<"Not Unique!"<<endl; break; } edge[i].del=0; } } if(i>=m) cout<<ans<<endl; } return 0; }