首页 > 代码库 > 算法训练 安慰奶牛 最小生成树+构造

算法训练 安慰奶牛 最小生成树+构造

http://lx.lanqiao.cn/problem.page?gpid=T16

题意:n个点,p条边,n,p<=1e5.每个点都有权值c[i],求选择一个点出发遍历所有点后返回需要的最小代价?

容易发现 每条边都经历了两次,边(u,v) 第一次达到v时ans+=c[v],v返回u时ans+=c[u] 则构造边为:安慰两个点(u,v)的代价为 2*w+c[u]+c[v],求出MST即可

#include <bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int N=2e5+20;
struct node{
	int u,v,w;
}e[N];
int n,p,c[N],d[N],vis[N],ans;
int fa[N];
bool cmp(node a,node b)
{
	return a.w<b.w;
}
int find(int x)
{
	if(fa[x]!=x)
		fa[x]=find(fa[x]);
	return fa[x];
}
void Union(int x,int y)
{
	int fx=find(x),fy=find(y);
	fa[fx]=fy;
}
//每次用最小代价把两个连通分量合成一个 
void Kruskal()
{
	for(int i=1;i<=n;i++)
		fa[i]=i;
	sort(e,e+p,cmp);
	for(int i=0;i<p;i++)
	{
		int u=e[i].u,v=e[i].v,w=e[i].w;	
		if(find(u)!=find(v))
		{
			Union(u,v);
			ans+=w;
		}
	}		
}
int main()
{
	while(cin>>n>>p)
	{
		int mn=inf;
		ans=0;
		int u,v,w;
		for(int i=1;i<=n;i++)
		{
			cin>>c[i];
			mn=min(c[i],mn);//选择slepp的地方,起点 
		}
		for(int i=0;i<p;i++)
		{
			cin>>u>>v>>w;
			e[i].u=u,e[i].v=v;
			e[i].w=2*w+c[u]+c[v];//安慰u,v两个奶牛所需要的时间 
		}
		Kruskal();
		memset(vis,0,sizeof(vis));
		cout<<ans+mn<<endl;
		 
	}
	return 0;
}

  

算法训练 安慰奶牛 最小生成树+构造