洛谷P1550 [USACO08OCT]打井Watering Hole
题目背景
John的农场缺水了!!!
题目描述
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 需要为连通整个牧场的每一块田地所需要的钱数。
输入输出格式
输入格式:
第1 行为一个整数n。
第2 到n+1 行每行一个整数,从上到下分别为W_1 到W_n。
第n+2 到2n+1 行为一个矩阵,表示需要的经费(P_ij)。
输出格式:
只有一行,为一个整数,表示所需要的钱数。
输入输出样例
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0
9
说明
John等着用水,你只有1s时间!!!
————————————————————————
这道题有个非常秒的转换 就是新建一个S作为河水
把所有的村庄和S连边 代价是打井的费用
然后就变成了一道最小生成树了
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=507; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,S,f[M],x; LL ans; int find(int x){return f[x]==x?x:f[x]=find(f[x]);} struct node{int to,from,next,w;}e[M*M]; bool cmp(node a,node b){return a.w<b.w;} int first[M],cnt,sum; void ins(int a,int b,int w){cnt++; e[cnt].from=a; e[cnt].to=b; e[cnt].next=first[a]; e[cnt].w=w; first[a]=cnt;} int main() { n=read(); S=n+1; for(int i=1;i<=S;i++) f[i]=i; for(int i=1;i<=n;i++) x=read(),ins(S,i,x); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ x=read(); if(j<i) ins(i,j,x); } sort(e+1,e+1+cnt,cmp); for(int i=1;i<=cnt;i++){ int x=find(e[i].from),y=find(e[i].to); if(x==y) continue; f[y]=x; ans+=(LL)e[i].w; sum++; if(sum==S) break; }printf("%lld\n",ans); return 0; }