*(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);
}