【BZOJ1061】[Usaco2008 Oct] 灌水

描述 Description

Farmer John 已经决定把水灌到他的 n(1<=n<=300) 块农田,农田被数字 1 到 n 标记。把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库。 建造一个水库需要花费 wi(1<=wi<=100000), 连接两块土地需要花费 Pij(1<=pij<=100000,pij=pji,pii=0). 计算 Farmer John 所需的最少代价。

输入格式 InputFormat

第一行:一个数 n.

第二行到第 n+1 行:第 i+1 行含有一个数 wi.

第 n+2 行到第 2n+1 行:第 n+1+i 行有 n 个被空格分开的数,第 j 个数代表 pij。

输出格式 OutputFormat

第一行:一个单独的数代表最小代价.

样例输入 SampleInput

10
537
914
269
536
882
245
172
615
367
688
0 56 91 16 53 82 30 52 51 51
56 0 36 24 12 41 67 50 37 99
91 36 0 96 6 34 2 60 74 58
16 24 96 0 25 27 8 79 34 14
53 12 6 25 0 12 23 30 44 7
82 41 34 27 12 0 79 68 87 66
30 67 2 8 23 79 0 39 32 14
52 50 60 79 30 68 39 0 57 38
51 37 74 34 44 87 32 57 0 1
51 99 58 14 7 66 14 38 1 0

样例输出 SampleOutput

266

来源 Source

资格赛


BZOJ 1061


代码 Code

添加虚拟点 0 与每块土地连边,权值为该块土地建造水库的费用。跑一边 MST 即可。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
struct path
{
    int z,y,x;
}a[100000];
int fa[305];
int i,j,t,n,m,l,r,k,ans;
bool comp(path a,path b)
{
    return a.z<b.z;
}
int getfa(int s)
{
    if (fa[s]==s) return s;
    else fa[s]=getfa(fa[s]);
    return fa[s];
}
void mst()
{
    int i,j,t;
    sort(a+1,a+m+1,comp);
    for (i=1;i<=m;i++) if (getfa(a[i].x)!=getfa(a[i].y))
    {
        ans+=a[i].z;
        fa[getfa(a[i].x)]=a[i].y;
    }
}
int main()
{
    scanf("%d",&n);
    m=0;
    for (i=0;i<=n;i++) fa[i]=i;
    for (i=1;i<=n;i++) 
    {
        scanf("%d",&t);
        a[++m].x=0;a[m].y=i;a[m].z=t;
    }
    for (i=1;i<=n;i++) for (j=1;j<=n;j++)
    {
        scanf("%d",&t);
         if (i<j) 
         {
            a[++m].x=i;a[m].y=j;a[m].z=t;
         }
    }
    ans=0;
    mst();
    printf("%d\n",ans);
    return 0;
}