题意:
判断最小生成树是否唯一。
思路:
首先求出最小生成树,记录现在这个最小生成树上所有的边,然后通过取消其中一条边,找到这两点上其他的边形成一棵新的生成树,求其权值,通过枚举所有可能,通过这些权值看与原最小生成树的权值比较看其是否唯一。其实也可以理解成次小生成树加上最大边权的边后是否唯一。
代码:
krusual:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const int N=11000; const int M=15005; int i,j,n,m,cnt,parent[N]; bool flag; struct man { int u,v,w; int eq,used,del; } edg[N]; bool cmp(man g,man h) { return g.w<h.w; } void init() { for(i=0; i<=10005; i++) { parent[i]=i; } } int Find(int x) { if(parent[x] != x) parent[x] = Find(parent[x]); return parent[x]; }//查找并返回节点x所属集合的根节点 void Union(int x,int y) { x = Find(x); y = Find(y); if(x == y) return; parent[y] = x; }//将两个不同集合的元素进行合并 int Kruskal() { init(); int sum=0; int num=0; for(i=0;i<m;i++) { if(edg[i].del==1)continue; int u=edg[i].u;int v=edg[i].v;int w=edg[i].w; if(Find(u)!=Find(v)) { sum+=w; if(!flag)edg[i].used=1; num++; Union(u,v); } if(num>=n-1)break; } return sum; } int main() { int t; cin>>t; while(t--) { cnt=0; cin>>n>>m; for(i=0; i<m; i++) { cin>>edg[i].u>>edg[i].v>>edg[i].w; edg[i].del=0; edg[i].used=0; edg[i].eq=0;//eq没有初始化 } for(i=0;i<m;i++) { for(j=0;j<m;j++) { if(i==j)continue; if(edg[i].w==edg[j].w)edg[i].eq=1; } } sort(edg,edg+m,cmp); flag=false; cnt=Kruskal(); flag=true; bool gg=false; for(i=0;i<m;i++) { if(edg[i].used==1&&edg[i].eq==1) { edg[i].del=1; int s=Kruskal();//printf("%d %d ",i,s); if(s==cnt) { gg=true; cout<<"Not Unique!"<<endl; break; } edg[i].del=0; } } if(!gg) cout<<cnt<<endl; } return 0; }