挖水井

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。

(图片掉了,只好自己想象)

【思路】
将N个点连起来求最小值就是kruskal,可是有点的可以和其他的相连或者是挖水井
那这样怎么用kruskal呢.....
虚拟一个点为水源 将虚拟的点和每个点连起来,边的权值是挖水井的费用。
将这n+1个点连起来,无论怎么连,虚拟的那个点(即水源)我们一定连进去了。哪个点和虚拟的点连起来就是挖水井的点。
【代码】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int num,all,far[10000],n,w[10000];

struct edge
{
    int q,z,v;
}E[100000];

void add(int q,int z,int v)
{
    num++;
    E[num].q=q;E[num].z=z;E[num].v=v;
}

int f(int x)
{
    return far[x]==x?x:f(far[x]);
}

void unionn(int x,int y)
{
    int xf=f(x),yf=f(y);
    far[xf]=yf;
}

bool cmp(const edge a,const edge b)
{
    return a.v<b.v;
}

void kruskal()
{
    int js=0;
    sort(E+1,E+num+1,cmp);
    for(int i=1;i<=num;i++)
    {
        if(f(E[i].q)!=f(E[i].z))
        {
            js++;
            all+=E[i].v;
            unionn(E[i].q,E[i].z);
        }
        if(js==n)
        break;
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        far[i]=i;
        scanf("%d",&w[i]);
    }
    int g;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&g);
            if(g)
            add(i,j,g);
        }
    }
    for(int i=1;i<=n;i++)
    {
        add(i,n+1,w[i]);
        add(n+1,i,w[i]);
    }
    kruskal();
    printf("%d",all);
    return 0;
    
}
原文地址:https://www.cnblogs.com/zzyh/p/6773320.html