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;
}
}
}