所需前置知识:邴茶吉
我个人觉得把所有东西写成函数会更方便
大多数简单的生成树都要写这些东西:
建结构体——>给结构体写比较函数
一模一样的并查集模板
重点的kruskal分为以下几步:
1.循环看始点和重点是否为同一连通块
2.否——接入
f[u]=v
3.计数并判断是否形成了最小生成树
粘一个正经描述
当然本题不可能完全是个模板,我们看题之后会发现要重复计算忽悠时间,并在输出时多算一个始点
之后看代码
#include<bits/stdc++.h>
using namespace std;
int f[100005],u,v,ans,n,m,total,t[100005];
struct xxx{//结构体部分,定义道路的始点,终点和忽悠时间……
int start,end;
long long l;
}road[100005];
int find(int x){//邴茶吉模板
if(f[x]==x)
return x;
else
f[x]=find(f[x]);
return f[x];
}
bool cmp(xxx a,xxx b){//自定义比较函数,sort要用
return a.l<b.l;
}
void kruskal(){//kruskal
for(int i=1;i<=m;i++){
u=find(road[i].start);
v=find(road[i].end);
if(u==v)
continue;//两点属于同一个连通块,直接进入下个情况
ans+=road[i].l;
f[u]=v;//不在同一个连通块,就接入连通块
total++;
if(total==n-1){//形成了最小生成树
break;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=n;i++){
cin>>t[i];
}
for(int i=1;i<=m;i++){
cin>>road[i].start>>road[i].end>>road[i].l;
road[i].l=road[i].l*2+t[road[i].start]+t[road[i].end];//题中描述的道路要忽悠两遍,并加上开始和结束的点
}
sort(road+1,road+1+m,cmp);
kruskal();
sort(t+1,t+1+n);//像我这种懒得处理的可以直接排序找出发点
cout<<ans+t[1];//记得加上
return 0;
}