[USACO] 打井 Watering Hole

题目描述

Farmer John has decided to bring water to his N (1 <= N <= 300) pastures which are conveniently numbered 1..N. He may bring water to a pasture either by building a well in that pasture or connecting the pasture via a pipe to another pasture which already has water.

Digging a well in pasture i costs W_i (1 <= W_i <= 100,000).

Connecting pastures i and j with a pipe costs P_ij (1 <= P_ij <= 100,000; P_ij = P_ji; P_ii=0).

Determine the minimum amount Farmer John will have to pay to water all of his pastures.

POINTS: 400

农民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 需要为使所有农场都与有水的农场相连或拥有水井所需要的钱数。

题目解析

一眼看上去很麻烦,但是只要想到了其实很简单,最小生成树而已。

加一个点作为井,跑最小生成树,虽然不是很快但对于这道题绰绰有余了(110ms / 10*1s)

思路好题

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int MAXN = 300 + 5;

struct Edge {
    int from,to;
    int w;
    friend bool operator < (Edge x,Edge y) {
        return x.w < y.w;
    }
} l[MAXN*MAXN];

int n,ans;
int fa[MAXN];
int cnt;

inline int find(int x) {
    if(fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}

inline void add(int x,int y,int z) {
    cnt++;
    l[cnt].from = x;
    l[cnt].to = y;
    l[cnt].w = z;
    return;
}

int main() {
    scanf("%d",&n);
    int x;
    for(int i = 1;i <= n;i++) {
        scanf("%d",&x);
        add(i,n+1,x);
    }
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= n;j++) {
            scanf("%d",&x);
            if(i == j) continue;
            add(i,j,x);
        }
    }
    for(int i = 1;i <= n+1;i++) fa[i] = i;
    sort(l+1,l+1+n*n);
    int num = 0;
    for(int i = 1;i <= n*n && num <= n;i++) {
        if(find(l[i].from) == find(l[i].to)) continue;
        num++; ans += l[i].w;
        fa[find(l[i].from)] = find(l[i].to);
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-09-28 20:19  Floatiy  阅读(431)  评论(0编辑  收藏  举报