185. [USACO Oct08] 挖水井

185. [USACO Oct08] 挖水井

★★   输入文件:water.in   输出文件:water.out   简单对比
时间限制:1 s   内存限制:128 MB

农夫约翰决定给他的N(1<=N<=300)个牧场浇水,这些牧场被自然的命名为1..N。他可以给一个牧场引入水通过在这个牧场挖一口井或者修一条管道使这个牧场和一个已经有水的牧场连接。

在牧场i挖一口井的花费是w_i(1<=w_i<=100000)。修建一条水管连接牧场i和牧场j的花费是p_ij(1<=p_ij<=100000;p_ij=p_ji;p_ii=0)。

请确定农夫约翰为了完成浇灌所有的牧场所需的最小的总花费。

题目名称:water

输入格式:

  • 第1行:一个单独的整数n。
  • 第2..n+1行:第i+1行包含一个单独的整数w_i。
  • 第n+2..2n+1行:第n+1+i行包含n个用空可分开的整数;其中第j个数是p_ij。

输入样例(file water.in):

4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0

输入说明:

这里有4个牧场,修井和修管道的代价如图。

输出格式:

  • 第1行:一个单独的整数,表示花费。

输出样例(file water.out):

9

输出说明:

农夫约翰可以在第4个牧场修井,并且将每个牧场和第一个连接起来,这样,花费是3+2+2+2=9。

 

思路:建立一个超级源点,于每个节点连边,然后跑最小生成树。

错因:无。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100000
using namespace std;
int n,ans,num,tot,fa[MAXN];
struct nond{
    int x,y,z;
}edge[MAXN];
int cmp(nond a,nond b){
    return a.z<b.z;
}
int find(int x){
    if(fa[x]==x)    return fa[x];
    else return fa[x]=find(fa[x]);
}
int main(){
    freopen("water.in","r",stdin);
    freopen("water.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int w;
        scanf("%d",&w);
        edge[++tot].x=0;
        edge[tot].y=i;
        edge[tot].z=w;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            int w;
            scanf("%d",&w);
            edge[++tot].x=i;
            edge[tot].y=j;
            edge[tot].z=w;
        }
    sort(edge+1,edge+1+tot,cmp);
    for(int i=0;i<=n;i++)    fa[i]=i;
    for(int i=1;i<=tot;i++){
        int dx=find(edge[i].x);
        int dy=find(edge[i].y);
        if(dx==dy)    continue;
        fa[dx]=dy;
        num++;
        ans+=edge[i].z;
        if(num==n)    break;
    }
    cout<<ans;
}

 

posted @ 2017-08-23 10:34  一蓑烟雨任生平  阅读(239)  评论(0编辑  收藏  举报