版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82748090
特殊Kruskal最小生成树
不难发现,不考虑最后回到起点,每个点要被经过度数次,也就是说一条边连接两个点 ,这两个点要各被经过一次,所以我们将一条边的边权就可以变成边权*2+cost[x]+cost[y]也就是说经过两遍,再加上一开始救人时爬坑的花费,然后显然爬出起点的花费最小最优,所以我们找一个爬出时间最小的点当起点,跑最小生成树即可
代码
//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=200500;
struct edge
{
int to,fr,cost;
bool friend operator < (edge a,edge b)
{
return a.cost>b.cost;
}
}ad,no;
priority_queue<edge>q;
int n,m;
int fa[M],siz[M],t[M];
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline int find(int x)
{
if (x!=fa[x]) return fa[x]=find(fa[x]);
return x;
}
inline void unionn(int x,int y)
{
if (siz[x]<siz[y]) siz[y]+=siz[x],fa[x]=y;
else siz[x]+=siz[y],fa[y]=x;
return ;
}
inline void constt()
{
for (int i=1;i<=n;i++) siz[i]=1,fa[i]=i;
return ;
}
inline void Kru(int x)
{
constt();int cnt=0,ans=0;
while (q.size()&&cnt<n)
{
no=q.top();q.pop();
int r1=find(no.fr);
int r2=find(no.to);
if (r1!=r2)
unionn(r1,r2),cnt++,ans+=no.cost;
}
cout<<ans+x;
return ;
}
signed main()
{
n=read();m=read();int mi=2e9;
for (int i=1;i<=n;i++)
t[i]=read(),mi=min(mi,t[i]);
for (int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
ad.fr=x,ad.to=y,ad.cost=z*2+t[x]+t[y];
q.push(ad);
}
Kru(mi);
return 0;
}