1930. 灌溉农田(irrigation)

1930. 灌溉农田(irrigation)

题目描述
由于最近缺少降雨,农夫约翰决定在他的N块农田之间建立一个供水管网。每块的位置可以用一个二维坐标来表示(xi,yi),在第i块地和第j块地之间修建一个管道的话,代价是(xi - xj)^2 + (yi - yj)^2。农夫约翰想要建立一个花费代价最小的供水管网,使得他所有的地都能被连接在一起(使得水能够通过一系列的管道流到各个田地里去)。不幸的是,建造管道的人拒绝建造花费代价小于C的单条管道。请帮助约翰计算最少需要花费多少代价,才能建成这个供水管网。

输入
第一行是两个正整数N和C。
第2行到第N+1行,每行两个整数,表示xi和yi。

输出
输出建立供水管网的最小代价,如果不能建立供水管网,就输出-1。

样例输入

3 11 
0 2 
5 0 
4 3

样例输出

46

数据范围限制
1<=N<=2000,0<=xi,yi<=1000。

提示
样例中,约翰不能在(4,3)和(5,0)之间建立管道,因为这个管道的代价是10。因此,他只能在(0,2)和(5,0)之间修建一条管道,花费是29,在(0,2)和(4,3)之间修建一条管道,花费是17,所以总的最小花费是29+17=46。

思路:
这是一道典型的最小生成树。因为农夫想要代价最小,所以只需n-1条边,然后保证n-1条边权和最小。故可以用最小生成树。
唯一考虑只有边权>=花费代价C,才能加边。

#include<cstdio>
#include<iostream>
#include<cstring>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int INF=2147483647;
long long n,m,a[2010],b[2010],c[2010][2010],lowcost[2010],ans,ds;
bool vis[2010];
void input()
{
	memset(c,127,sizeof(c));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i],&b[i]);
		for(int j=1;j<i;j++)
		{
			int t=(a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]);
			if(t>=m) c[i][j]=c[j][i]=t;
		}			
	}
}
void Prim()
{
	int v=1;
	vis[v]=1;
	for(int i=1;i<=n;i++) lowcost[i]=c[v][i];
	for(int i=1;i<n;i++)  
	{
		int temp=INF,t;
		for(int j=1;j<=n;j++)
			if(lowcost[j]<temp&&!vis[j])
				temp=lowcost[j],t=j;
		if(temp==INF) continue;
		vis[t]=1,v=t,ans+=temp,ds++;
		for(int j=1;j<=n;j++)
			if(lowcost[j]>c[v][j]&&!vis[j]) 
			lowcost[j]=c[v][j];
	}
}
int main()
{
	fre(irrigation);
	input();
	Prim();
	if(ds==n-1) printf("%d",ans);
	else printf("-1");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/bigwinner888/article/details/106958254