TYVJ1659中中救援队

特殊Kruskal最小生成树

不难发现,不考虑最后回到起点,每个点要被经过度数次,也就是说一条边连接两个点 ,这两个点要各被经过一次,所以我们将一条边的边权就可以变成边权*2+cost[x]+cost[y]也就是说经过两遍,再加上一开始救人时爬坑的花费,然后显然爬出起点的花费最小最优,所以我们找一个爬出时间最小的点当起点,跑最小生成树即可

代码

//By AcerMo
#include
#include
#include
#include
#include
#include
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;
}

你可能感兴趣的:(图论-最小生成树)