Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 16068 | Accepted: 5566 |
Description
Input
Output
Sample Input
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
Sample Output
3 Not Unique!
Source
思路:按并查集,先解出第一次的最小树,然后标记所有用过的边,和所具有相同权值的边。然后依次删除用过的具有相同权值的边,看最小生成树的值是不是一样,一样则最 小树不唯一。
易错点:权值全为0 要注意。
2
3 2
1 2 0
2 3 0
3 3
1 2 0
2 3 0
1 3 0
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int mm=110000; const int oo=1e9; int root[mm],ran[mm]; class node { public:int u,v,c; bool used,equ,del; node(){used=equ=del=0;} }edge[mm]; int m,n,cen; bool cmp(node a,node b) { return a.c<b.c; } int look(int x) { if(x^root[x])root[x]=look(root[x]); return root[x]; } void uni(int x,int y) { if(ran[look(x)]>ran[look(y)])root[look(y)]=look(x),ran[look(x)]+=ran[look(y)]; else root[look(x)]=look(y),ran[look(y)]+=ran[look(x)]; } int kruskal() { cen++;int sum=0,num=0; for(int i=0;i<m;i++) { if(edge[i].del)continue; if(look(edge[i].u)^look(edge[i].v)) {uni(edge[i].u,edge[i].v); sum+=edge[i].c;num++; if(cen==1) edge[i].used=1; } if(num>=n-1)break; } if(num<n-1)return -oo;///不能构成最小树 return sum; } void _set() { for(int i=0;i<=n;i++) root[i]=i,ran[i]=1; } int main() { int cas; while(cin>>cas) { while(cas--) { memset(edge,0,sizeof(edge)); cin>>n>>m; for(int i=0;i<m;i++) { cin>>edge[i].u>>edge[i].v>>edge[i].c; } for(int i=0;i<m;i++) for(int j=0;j<m;j++) if(i^j&&edge[i].c==edge[j].c) edge[i].equ=edge[j].equ=1; sort(edge,edge+m,cmp); _set();int ans=0,z; cen=0;ans=kruskal(); ///if(ans==-oo)ans=0; bool flag=1; for(int i=0;i<m;i++) { if(edge[i].used&&edge[i].equ) { _set(); edge[i].del=1;z=kruskal();edge[i].del=0; if(z==ans){flag=0;break;} } } if(!flag)cout<<"Not Unique!\n"; else cout<<ans<<"\n"; } } }