[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; }