(最小生成树)洛谷P2916 [USACO08NOV]安慰奶牛Cheering up the Cow

社会主义新天地 提交于 2020-02-08 19:06:25

一、算法分析

刚看到题的时候没什么头绪,然后先模拟了一下题上的例子,感觉本题基本框架还是最小生成树,但是需要预处理一下,刚开始的想法是把点权加到边权上面,好能求最小生成树。然后开始的实现方式就是把每个边的边权加上这个边的起点的点权,样例也能过。但是交上去之后只能过第一个点。说明这样的方法不对,那么就需要建模求解正确方法,建模时将点分为三类,起点(根)、叶子、中间点。可以证明在一个生成树中,根据题目中的走法,叶子的度数为1,且经过一次,中间点的度数等于其经过次数,叶子和中间点这两类点可以合并,但是起点会多经过(谈话)一次,然后每条边会经过两次。如果先不算起点多的那次的话,新的边权就可以设置成原来边权乘2再加上边的起点和终点权值,然后跑一遍最小生成树,把最小生成树上所有边权加起来即可。然后再算多起点多出来的那一次,因为起点是可以自定的,所以要想谈话时间最小,那就可以把点权最小的点作为起点。所以最终答案就是最小生成树中,预处理后的新边权和再加上最小点权。

二、代码及注释

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=10050;            
int pa[maxn];
int r[maxn];
int n,m;
int findy(int x){                           //并查集板子 
	if(x==pa[x]) return x;
	int root=findy(pa[x]);
	return pa[x]=root;
} 
bool pd(int x,int y){
	int xx=findy(x);
	int yy=findy(y);
	return xx==yy;
}
void uni(int x,int y){
	int xx=findy(x);
	int yy=findy(y);
	if(xx!=yy){
		if(r[xx]==r[yy]){
			r[yy]++;
		}
		else if(r[xx]>r[yy]) swap(xx,yy);
		pa[xx]=yy;
		r[yy]+=r[xx];
	}
}
struct node{                           //边 
	int from;
	int to;
	int val;
	node(int u,int v,int d):from(u),to(v),val(d){}
	node():from(0),to(0),val(0){}
};
vector<node> a;
bool cmp(node x1,node x2){
	return x1.val<x2.val;
}
int val[maxn];                         //保存点权 
ll ans;
int main(){

	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) pa[i]=i;
	for(int i=1;i<=n;i++) scanf("%d",&val[i]);
	int u,v,d;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&d);
		a.push_back(node(u,v,d*2+val[u]+val[v]));
		a.push_back(node(v,u,d*2+val[v]+val[u]));
	}
	sort(a.begin(),a.end(),cmp);
  int len=a.size();
  int sum=0;
  for(int i=0;i<len;i++){               //跑一遍最小生成树 
  	if(!pd(a[i].from,a[i].to)){
  		sum++;
  		uni(a[i].from,a[i].to);
  		ans+=a[i].val;
		}
		if(sum==n-1) break;
	}
  int minx=val[1];
  for(int i=1;i<=n;i++) minx=min(minx,val[i]);
  ans+=minx;
	printf("%lld",ans);
	
	return 0;
	
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!