[jzoj 5353] 村通网 {kruskal算法}

Description

为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里每座建筑都连上互联网,方便未来随时随地网购农药。
他的农庄很大,有N 座建筑,但地理位置偏僻,网络信号很差。
一座建筑有网,当且仅当满足以下至少一个条件:
1、给中国移动交宽带费,直接连网,花费为A。
2、向另外一座有网的建筑,安装共享网线,花费为B×两者曼哈顿距离。
现在,农夫约已经统计出了所有建筑的坐标。他想知道最少要多少费用才能达到目的。

Input

第一行:三个正整数,代表N、A、B。
接下来N 行:每行两个整数Xi、Yi,第i 行代表第i 座建筑的坐标。

Output

第一行:一个整数,代表答案。


解题思路

显然我们是可以(假想)让所有坐标连在一起(直接连网的可以看做连一条代价为A的边)。 我们可以先暴力连边,然后,从小到大排序。显然(在kruskal中),越在前面的边的边权值越小,也就是说权值小于A的边都是可以先连成一颗子最小生成树。然后我们就可以直接处理直接连网的边,自然是子最小生成树的个数*A,加上ans就是最后的答案
注意范围,在比赛时,我就因为范围的问题WA了


代码

#include<cstdio>
#include<algorithm>
#define rr register 
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
struct node{int x,y,z,next;}a[1000001];
int len,n,A,B,f[2001],head[2001],ans,tg,xg[2001],yg[2001]; 
inline int found(int x){return f[x]==x?f[x]:f[x]=found(f[x]);}
inline int minn(int x,int y){return x<y?x:y;}
inline int abss(int x){return x>=0?x:-x;}
void add(int x,int y,int z){a[++len]=(node){x,y,z,head[x]}; head[x]=len;}
inline bool cmp(node x,node y){return x.z<y.z;}
int main()
{
	file(pupil); 
	scanf("%d%d%d",&n,&A,&B); 
	for(rr int i=1;i<=n;f[i]=i,i++) scanf("%d %d",&xg[i],&yg[i]); 
	for(rr int i=1;i<=n;i++)
	 for(rr int j=1;j<=n;j++)
	 if (i!=j) add(i,j,(abss(xg[i]-xg[j])+abss(yg[i]-yg[j]))*B);
	sort(a+1,a+len+1,cmp); 
	for(rr int i=1;i<=len;i++) 
	 {
	 	int xx=found(a[i].x),yy=found(a[i].y); 
	 	if (xx!=yy) {
			f[yy]=xx; 
	 		if (a[i].z<=A) {
	 			ans+=a[i].z; tg++; 
			 } else	{
				 printf("%d",ans+A*(n-tg));
			 	 return 0;
			 }
		 }
	 	if (tg==n-1) {
		 	printf("%d",ans); 
	 		return 0; 
		 }
	 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值