题目描述:给定一个无向图,要求判断该图的最小生成树是否唯一,如果唯一的话输出最小生成树的权值,如果不唯一,输出Not Unique!解题思路:要判断最小生成树是否唯一,可以求出次小生成树,看权值是否和最小生成树相等,如果相等的话说明最小生成树不唯一,否则说明最小生成树是唯一的,那么,只要求出次小生成树来就好办了。我用的是Kruskal算法求出最小生成树来,然后依次枚举这些树边并去掉,再求最小生成树,所得的这些值的最小值就是次小生成树的值,当然,前提是去掉一条树边以后,剩下的边可以形成次小生成树。ps:这题糊里糊涂就过了,不知道是不是数据太弱,我总感觉自己考虑不周全,却不知道在哪里……
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,cas;
struct node
{
int u,v,w;
}edge[10000];
int sum,num;
int mst,smst=0x7fffffff;//mst----最小生成树权值smst----次小生成树权值
bool v[10000],can[10001];//v记录是不是最小生成树的树边,can记录能否在求次小生成树时用到某边
int p[10001],rank[10001];
int Makeset()
{
int i;
for(i=1;i<=n;i++)
{
p[i]=i;
rank[i]=0;
}
return 0;
}
int Find(int t)
{
if(t!=p[t])
{
p[t]=Find(p[t]);
}
return p[t];
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
int Union(int a,int b)
{
int x=Find(a);
int y=Find(b);
if(rank[x]>rank[y])
{
p[y]=x;
}
else
{
p[x]=y;
if(rank[x]==rank[y])
{
rank[y]++;
}
}
return 0;
}
int Kruskal()
{
num=0;
sum=0;
Makeset();
int i;
for(i=0;i<m;i++)
{
if(Find(edge[i].u)!=Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum+=edge[i].w;
v[i]=1;
num++;
}
if(num==n-1)
break;
}
return sum;
}
int Sec_Kruskal()
{
num=0;
sum=0;
int i;
Makeset();
for(i=0;i<m;i++)
{
if(can[i])
{
if(Find(edge[i].u)!=Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum+=edge[i].w;
num++;
}
if(num==n-1)
break;
}
}
return sum;
}
int main()
{
int i,j;
scanf("%d",&cas);
while(cas--)
{
smst=0x7fffffff;
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
memset(can,1,sizeof(can));
memset(v,0,sizeof(v));
sort(edge,edge+m,cmp);
mst=Kruskal();
for(i=0;i<m;i++)
{
if(v[i])
{
can[i]=0;
int tmp=Sec_Kruskal();
if(tmp>=mst&&smst>tmp)//如果tmp<mst说明不能形成次小生成树
{
smst=tmp;
}
can[i]=1;
}
}
if(mst==smst&&smst!=0)
{
printf("Not Unique!\n");
}
else
{
printf("%d\n",mst);
}
//printf("%d %d\n",mst,smst);
}
//system("pause");
return 0;
}