题意:判断最小生成树是否唯一,
若唯一,输出最小权值和,否则,输出 Not Unique!
判断最小生成树是否唯一的思路:
1、对图中的每一条边,扫描其他边,如果存在相同权值的边,则对该边做标记
2、然后用Kruskal算法或Prim算法求MST
3、求得MST后,如果该MST中未包含做了标记的边,即可判断MST唯一;
如果包含做了标记的边,则依次去掉这些边的一条边,再求MST,
如果求得的MST权值和原来的MST的权值一样,即可判断MST不唯一。
个人思路是先求最小生成树,并标记最小生成树包含的边,
再依次判断是否有相同权值的边,若存在,将最小生成树的该条边去掉,
重新求最小生成树,若得到的权值与原来的最小权值和相等,则不唯一
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define INF 999999
using namespace std;
int n,m,k,f[105],path[105];
struct stu
{
int u,v,w;
}edge[10010];
int cmp(stu a,stu b)
{
return a.w<b.w;
}
int find(int x)
{
if(x!=f[x])
f[x]=find(f[x]);
return f[x];
}
int kruskal(int flag)
{
int i,x,y,sum=0;
for(i=1;i<=n;i++)
f[i]=i;
k=0;
for(i=1;i<=m;i++){
if(edge[i].w==INF)
continue;
x=find(edge[i].u);
y=find(edge[i].v);
if(x!=y){
sum+=edge[i].w;
if(flag)
path[k]=i; //第一次求最小生成树时记录路径
k++;
if(k==n-1)
break;
f[x]=y;
}
}
if(k!=n-1)
sum=-1;
return sum;
}
int main()
{
int T,i,j,ans,s,t,flag,num;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(edge,0,sizeof(edge));
for(i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+m+1,cmp);
ans=kruskal(1);
flag=1;
num=k;
for(i=0;i<num&&flag;i++){
j=path[i]; //依次判断是否存在与路径相同权值的边
if(edge[j-1].w==edge[j].w||edge[j+1].w==edge[j].w){
t=edge[j].w;
edge[j].w=INF; //若存在,将其标记为极大值,表示去掉此边,再求最小生成树
s=kruskal(0);
if(s==ans)
flag=0;
edge[j].w=t; //将该边还原为原值
}
}
if(!flag)
printf("Not Unique!\n");
else
printf("%d\n",ans);
}
return 0;
}