因为我们要学习算法的多样性,所以我们这道题采取更为简单的算法Kruskal具体代码讲解如下
#include<bits/stdc++.h>
using namespace std;
typedef struct Edge
{
int x,y,z;
}op;//定义输入方便的结构体x为起点,y为终点,z为权值
bool cmp(op a,op b)
{
return a.z<b.z;//以小为排序规则
}
int p[1000]; //并查集数组
int find(int x)//并查集
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
set<int>hi;//为的是找出对应集合
int main()
{
int a,b;cin>>a>>b;
for(int i=1;i<=a;i++)p[i]=i;//并查集始初化
op mp[250000];//定义的大一点容易溢出
int gp[1000];//这个是为了储存结点的距离方便之后减去操作
int vist[1000];//是否用过该边的一个判断数组
for(int i=0;i<b;i++)vist[i]=0;//始初化
int sum=0;
int cot=0;
for(int i=0;i<b;i++)
{
cin>>mp[i].x>>mp[i].y>>mp[i].z;//输入对应权值和出发起始点
}
sort(mp,mp+b,cmp);//排序
for(int i=0;i<b;i++)//开始算法
{
int as=find(mp[i].x);//找到祖宗
int ad=find(mp[i].y);//找到祖宗
if(as!=ad)//不是一个祖宗构不成环
{
p[as]=ad;//组成一个环
cot++;//边数加1
sum+=mp[i].z;//总距离加起来
vist[i]=1;//该边使用过
gp[mp[i].x]=gp[mp[i].y]=mp[i].z;//保存对应边值
}
}
if(cot<a-1)//如果边数使用太少则不能全部相连
{
for(int i=1;i<=a;i++)
{
hi.insert(find(i));//插入每一个的祖宗
}
cout<<"No MST"<<endl;
cout<<hi.size();//输出祖宗数量,即集合树数
return 0;
}
cout<<sum<<endl;//反之则可以构成最小树
for(int i=0;i<b;i++)
{
if(!vist[i])//如果该边没用过则交换去除一个边加上可以替代的另一个边
{
int as=mp[i].x;
int ad=mp[i].y;
int res=mp[i].z;
if(sum-gp[as]+res==sum)//如果成功被替代则不是唯一
{
cout<<"No";
return 0;
}
}
}
cout<<"Yes";//反之则是唯一
}