直接上中文题目
该题目主要是考察判断最小生成树是否唯一;
判断方法:将所有重复出现的边进行标记一下,然后求一边克鲁斯卡尔,如果说得到的最小生成树中所有的边的长度都不是重复出现的话,那最小生成树唯一,否则,枚举最小生成树中的每一条边,将该条边去掉后再求一遍最小生成树,如果可以再次构建出一颗生成树并且其权值之和恰好和之前的最小生成树权值之和相等,那么最小生成树就不唯一,否则唯一。
这个思路说难也不难,不过是第一次遇到然后就懵逼了QAQ,说真的感觉这个算法时间复杂度有点高,这个题数据也比较水,还需要再练!
上代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
const int N =1e6+10;
int n,m;
struct node {
int u,v,w;
}edge[5010];
bool cmp(struct node a,struct node b)
{
return a.w<b.w;
}
int p[110];
bool st[5010],vis[5010];
int find(int x)
{
if(x!=p[x])
p[x]=find(p[x]);
return p[x];
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
memset(st,false,sizeof st);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+1+m,cmp);
int ans1=0;
for(int i=1;i<=n;i++)
p[i]=i;
int flag=0;
for(int i=1;i<=m;i++)
{
int u=edge[i].u,v=edge[i].v,w=edge[i].w;
int fu=find(u);
int fv=find(v);
if(fu!=fv)
{
p[fu]=fv;
ans1+=w;
st[i]=true;
}
}
int cnt=0,flag1=0;
for(int i=1;i<=m;i++)
{
if(st[i])
{
vis[i]=true;
for(int j=1;j<=n;j++)
p[j]=j;
int ans2=0,cnt=0;
for(int j=1;j<=m;j++)
{
if(vis[j])
continue;
int u=edge[j].u,v=edge[j].v,w=edge[j].w;
int fu=find(u);
int fv=find(v);
if(fu!=fv)
{
p[fu]=fv;
ans2+=w;
cnt++;
}
}
vis[i]=false;
if(ans2==ans1&&cnt==n-1)
{
flag1=1;
break;
}
}
}
if(flag1)
cout<<"Not Unique!"<<endl;
else
cout<<ans1<<endl;
}
return 0;
}