想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:给出n个点,m条边,每条边有相应的权值,问这个图的最小生成树是否唯一
解题思路:先求出原图的最小生成树,标记哪些边是这个最小生成树的边,然后去掉其中的一条边求图的最小生成树,看和原图的最小生成树是否相等,如果有一个相等,那么输出Not Unique!,如果都不想等,那么输出最小生成树就可以了
/*
Memory 248K
Time 16MS
*/
#include<iostream>
using namespace std;
#define MAXV 110
#define MAXE 10100
typedef struct{
int s,t,w,flag;
}Edge;
Edge edge[MAXE];
int n,m;
int set[MAXV];
int cmp(const void *a,const void *b){
return ((Edge *)a)-((Edge *)b);
}
int find(int x){
int rt;
if(set[x]!=x){
rt=find(set[x]);
set[x]=rt;
return set[x];
}else return x;
}
bool Union(int a,int b){
int fa,fb;
fa=find(a);
fb=find(b);
if(fa==fb) return 0;
set[fa]=fb;
return 1;
}
int kruskal(){
int i,num=0,cnt=0;
for(i=0;i<=n;i++) set[i]=i;
for(i=0;i<m;i++){
if(Union(edge[i].s,edge[i].t)){
num+=edge[i].w;
edge[i].flag=1; //标记这条边是最小生成树的边
if(++cnt==(n-1)) break;
}
}
if(cnt==n-1) return num;
return -1; //如果没有最小生成树
}
int kruskalt(){
int i,num=0,cnt=0;
for(i=0;i<=n;i++) set[i]=i;
for(i=0;i<m;i++){
if(Union(edge[i].s,edge[i].t)){
num+=edge[i].w;
if(++cnt==(n-1)) break;
}
}
if(cnt==n-1) return num;
return -1;
}
int main(){
int i,s,ans,tmp;
int Case;
scanf("%d",&Case);
while(Case--){
scanf("%d%d",&n,&m);
for(i=0;i<m;i++){
scanf("%d%d%d",&edge[i].s,&edge[i].t,&edge[i].w);
edge[i].flag=0;
}
qsort(edge,m,sizeof(edge[0]),cmp);
ans=kruskal();
for(i=0;i<m;i++){
if(edge[i].flag){ //判断去除i边的图的最小生成树是否与前面最小生成树相等
s=edge[i].s;
edge[i].s=edge[i].t; //两个顶点相等不会加入最小生成树里面了
tmp=kruskalt();
if(tmp!=-1 && ans==tmp) break;
edge[i].s=s; //记得还原
}
}
if(i==m) printf("%d\n",ans);
else printf("Not Unique!\n");
}
return 0;
}