http://poj.org/problem?id=1679
题意 给出一个图 找出其最小生成树 若有多颗值一样的最小生成树 则输出 -1 若图不连通 则输出 0
先判断 图是否连通 若连通则 一定可以找到有n-1条边的 最小生成树
用克鲁斯卡尔 算法找最小生成树当找到第n-1 条时记下第n-1条边的权值 若后面有两端点在不同连通分量中 且其权值和前面记下的一样则 有多颗一样的
#include<iostream> #include<stdio.h> #include<queue> #include<vector> #include<string.h> using namespace std; struct E{ friend bool operator< (E n1, E n2) { return n1.w > n2.w; } int u;int v;int w; }edge[10000]; vector <int > g[102]; priority_queue < E > q; int n,f[102],vis[102]; int find(int a) { return f[a]==a?a:f[a]=find(f[a]); } int klu() { E temp; int ans=0,i,ff,a,b,cnt; for(i=0;i<=n;i++) f[i]=i; for( i=1;i<n;) // 找n-1 个 { temp=q.top (); a=find(temp.u) ; b=find(temp.v) ; if(a!=b) { if(i==n-1) ff=temp.w; else f[a]=b; ans+=temp.w; i++; } q.pop (); } cnt=0; while(!q.empty ()) { temp=q.top(); q.pop (); if(temp.w >ff) break; a=find(temp.u ); b=find(temp.v); if(a!=b) cnt++; if(cnt>0) return -1; } return ans; } void dfs(int s) { vis[s]=1; for(int i=0;i<g[s].size ();i++) if(!vis[g[s][i]]) dfs(g[s][i]); } int main() { int t,m,i,a,b,c,ans; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); edge[i].u=a; edge[i].v=b; edge[i].w=c; q.push(edge[i]); g[a].push_back (b); g[b].push_back (a); } int p=0; memset(vis,0,sizeof(vis)); //判断图是否连通
for(i=1;i<=n;i++) if(!vis[i]) { dfs(i); p++; } if(p>1) ans=0; else ans=klu(); if(ans==-1) printf("Not Unique! "); else printf("%d ",ans); while(!q.empty ()) q.pop (); for(i=1;i<=n;i++) g[i].clear (); } return 0; }