洛谷 P1550 [USACO08OCT]打井Watering Hole

来源:互联网 发布:python二分法 编辑:程序博客网 时间:2024/05/01 04:06

题目背景

John的农场缺水了!!!
题目描述

农民John 决定将水引入到他的n(1<=n<=300)个牧场。他准备通过挖若干井,并在各块田中修筑水道来连通各块田地以供水。在第i 号田中挖一口井需要花费W_i(1<=W_i<=100,000)元。连接i 号田与j 号田需要P_ij (1 <= P_ij <= 100,000 , P_ji=P_ij)元。

请求出农民John 需要为连通整个牧场的每一块田地所需要的钱数。
输入输出格式
输入格式:

第1 行为一个整数n。

第2 到n+1 行每行一个整数,从上到下分别为W_1 到W_n。

第n+2 到2n+1 行为一个矩阵,表示需要的经费(P_ij)。

输出格式:

只有一行,为一个整数,表示所需要的钱数。

输入输出样例
输入样例#1:

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

输出样例#1:

9

思路
最小生成树
需要注意的是不一定建一棵树,因为我们可以多棵树,挖多个井;
处理方法:设置一个超级原点,将各个井与超级原点连边,边权为打井所需花费,然后构建最小生成树。
证明:将打井费用作为边权,这样在做最小生成树时,就能直接选择打井(与超级原点相连)还是连边(与已打井相连),输出答案为所有边权。

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxn=310*310;struct node{    int x;int y;int v;}tu[maxn];int n,ans,num,tot,a;int fa[400],cost[maxn];bool cmp(node c,node d){    return c.v<d.v;}int father(int x){    if(fa[x]==x) return x;    return fa[x]=father(fa[x]);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d",&cost[i]);    }    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++){            scanf("%d",&a);{                if(i!=j){                    tu[++tot].v=a;                    tu[tot].x=i;tu[tot].y=j;                }                else {                    tu[++tot].v=cost[i];//与超级原点连边                    tu[tot].x=0;                    tu[tot].y=i;                }            }        }    for(int i=0;i<=n;i++)    fa[i]=i;    sort(tu+1,tu+tot+1,cmp);    for(int i=1;i<=tot;i++){        int xx=father(tu[i].x);int yy=father(tu[i].y);        if(xx!=yy){            ans+=tu[i].v;            fa[xx]=yy;            num++;        }        if(num==n) break;    }    printf("%d",ans);    return 0;}
0 0
原创粉丝点击