(纪中)1930. 灌溉农田(irrigation)【最小生成树】

*(File IO): input:irrigation.in output:irrigation.out
时间限制: 1000 ms 空间限制: 128000 KB 具体限制


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


输入
第一行是两个正整数NNCC
22行到第N+1N+1行,每行两个整数,表示xixiyiyi

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


样例输入
3 11
0 2
5 0
4 3

样例输出
46


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


提示
样例中,约翰不能在4,3(4,3)5,0(5,0)之间建立管道,因为这个管道的代价是1010。因此,他只能在0,2(0,2)5,0(5,0)之间修建一条管道,花费是2929,在0,2(0,2)4,3(4,3)之间修建一条管道,花费是1717,所以总的最小花费是29+17=4629+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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章