题目大意:
由于最近缺少降雨,农夫约翰决定在他的N块农田之间建立一个供水管网。
每块的位置可以用一个二维坐标来表示(xi,yi),在第i块地和第j块地之间修建一个管道的话,代价是(xi - xj)^2 + (yi - yj)^2。
农夫约翰想要建立一个花费代价最小的供水管网,使得他所有的地都能被连接在一起(使得水能够通过一系列的管道流到各个田地里去)。
不幸的是,建造管道的人拒绝建造花费代价小于C的单条管道。
请帮助约翰计算最少需要花费多少代价,才能建成这个供水管网。
思路:
这道题太太太太太太太太太太太太太明显是一道最小生成树的问题了。我们可以在计算两地之间的代价的同时,将代价小于c的路直接屏蔽(反正都不能用这条路),然后就是一道模板最小生成树的题目啦!
(建议用O(n^2),O(n^3) 10000%会超时)
代码:
#include
#include
#include
using namespace std;
int n,m,a[2001][2001],x[2001],y[2001],minn,k,sum,b[2001],c[2001],ans;
int main()
{
freopen("irrigation.in","r",stdin);
freopen("irrigation.out","w",stdout);
scanf("%d%d",&n,&m);
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])>=m)
a[i][j]=a[j][i]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); //计算两地之间的代价
}
b[1]=1;
for (int i=2;i<=n;i++)
c[i]=a[1][i]; //初始化
for (int j=1;j<=n-1;j++) //最小生成树
{
minn=999999998;
for (int i=1;i<=n;i++)
if (b[i]==0&&c[i]<=minn)
{
minn=c[i];
k=i;
}
b[k]=1;
sum+=c[k];
for (int i=1;i<=n;i++)
if (b[i]==0&&a[i][k]<=c[i]) //重新计算距离集合的最小代价
c[i]=a[i][k];
}
for (int i=1;i<=n;i++)
if (b[i]!=1)
{
printf("-1\n");
return 0;
}
printf("%d\n",sum);
return 0;
}