*(File IO): input:irrigation.in output:irrigation.out
时间限制: 1000 ms 空间限制: 128000 KB 具体限制
题目描述
由于最近缺少降雨,农夫约翰决定在他的N块农田之间建立一个供水管网。每块的位置可以用一个二维坐标来表示 ( x i , y i ) (xi,yi) (xi,yi),在第i块地和第j块地之间修建一个管道的话,代价是 ( x i − x j ) 2 + ( y i − y j ) 2 (xi - xj)^2 + (yi - yj)^2 (xi−xj)2+(yi−yj)2。农夫约翰想要建立一个花费代价最小的供水管网,使得他所有的地都能被连接在一起(使得水能够通过一系列的管道流到各个田地里去)。不幸的是,建造管道的人拒绝建造花费代价小于C的单条管道。请帮助约翰计算最少需要花费多少代价,才能建成这个供水管网。
输入
第一行是两个正整数 N N N和 C C C。
第 2 2 2行到第 N + 1 N+1 N+1行,每行两个整数,表示 x i xi xi和 y i yi yi。
输出
输出建立供水管网的最小代价,如果不能建立供水管网,就输出 − 1 -1 −1。
样例输入
3 11
0 2
5 0
4 3
样例输出
46
数据范围限制
1 < = N < = 2000 , 0 < = x i , y i < = 1000 1<=N<=2000,0<=xi,yi<=1000 1<=N<=2000,0<=xi,yi<=1000。
提示
样例中,约翰不能在 ( 4 , 3 ) (4,3) (4,3)和 ( 5 , 0 ) (5,0) (5,0)之间建立管道,因为这个管道的代价是 10 10 10。因此,他只能在 ( 0 , 2 ) (0,2) (0,2)和 ( 5 , 0 ) (5,0) (5,0)之间修建一条管道,花费是 29 29 29,在 ( 0 , 2 ) (0,2) (0,2)和 ( 4 , 3 ) (4,3) (4,3)之间修建一条管道,花费是 17 17 17,所以总的最小花费是 29 + 17 = 46 29+17=46 29+17=46。
解题思路
这道题就是一道最小生成树,可以采用普里姆算法.
代码
#include<bits/stdc++.h>
using namespace std;
int n,c,x[2020],y[2020],a[2020][2020],v[2020],b[2020],minn,k,ans;
int main()
{
freopen("irrigation.in","r",stdin);
freopen("irrigation.out","w",stdout);
scanf("%d%d",&n,&c);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
a[i][j]=999999999;
for(int i=1; i<=n; i++)
{
scanf("%d%d",&x[i],&y[i]);
for(int j=1; j<=i-1; j++)
if((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])>=c)
a[i][j]=a[j][i]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
v[1]=1;
for(int i=2; i<=n; i++)
b[i]=a[1][i];
for(int j=1; j<=n-1; j++)
{
minn=999999998;
for(int j=1; j<=n; j++)
if(v[j]==0&&b[j]<=minn)
{
minn=b[j];
k=j;
}
v[k]=1;
ans+=b[k];
for(int j=1; j<=n; j++)
if(v[j]==0&&a[j][k]<=b[j])
b[j]=a[j][k];
}
for(int i=1; i<=n; i++)
if(!v[i])
{
printf("-1");
return 0;
}
printf("%d",ans);
}