1. 程式人生 > >【Usaco2008 Oct】灌水 (最小生成樹)

【Usaco2008 Oct】灌水 (最小生成樹)

算法 操作 while 進行 題目 nbsp IT farm ostream

題目描述

Farmer John已經決定把水灌到他的n(1<=n<=300)塊農田,農田被數字1到n標記。把一塊土地進行灌水有兩種方法,從其他農田飲水,或者這塊土地建造水庫。 建造一個水庫需要花費wi(1<=wi<=100000),連接兩塊土地需要花費Pij(1<=pij<=100000,pij=pji,pii=0). 計算Farmer John所需的最少代價。

算法

最小生成樹

思路

每塊農田都有兩種操作方法:

1.在農田上修水庫

2.和別的農田連接

我們如果想要簡化問題的話,那麽最好的方法就是讓這兩個條件合並起來,所以在這裏,我們可以認為在田地修建水庫等效於新建立一個0號點,然後將0號點和每一個田地連接起來,這樣的話,要求求最小需要的代價就是將這一幅圖連成一個樹,這樣就能保證每個田地都能被灌溉到,因此做一遍最小生成樹即可。

代碼

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<map>
 7 using namespace std;
 8 struct nod{
 9     int fro,to,val;
10 };
11 nod a[150000];
12 int fa[600];
13 int cnt=0;
14 int n;
15
inline int read(){ 16 register int x=0; register char ch=getchar(); 17 while(ch<0||ch>9)ch=getchar(); 18 while(ch>=0&&ch<=9)x=x*10+ch-0,ch=getchar(); 19 return x; 20 } 21 inline int cmp(nod a,nod b){ 22 return a.val<b.val; 23 } 24 inline int getfa(int
x){ 25 if(fa[x]!=x)return fa[x]=getfa(fa[x]); 26 else return fa[x]; 27 } 28 inline void unio(int x,int y){ 29 fa[getfa(x)]=fa[y]; 30 } 31 int main(){ 32 n=read(); 33 nod temp; 34 for(register int i=1;i<=n;i++){ 35 temp.fro=0; temp.to=i; temp.val=read(); 36 a[++cnt]=temp; 37 } 38 for(register int i=1;i<=n;i++){ 39 for(register int j=1;j<=n;j++){ 40 register int x=read(); 41 if(i>j){ 42 temp.fro=i; temp.to=j; temp.val=x; 43 a[++cnt]=temp; 44 } 45 } 46 } 47 sort(a+1,a+cnt+1,cmp); 48 int ans=0; 49 for(register int i=0;i<=599;i++){ 50 fa[i]=i; 51 } 52 for(register int i=1;i<=cnt;i++){ 53 if(getfa(a[i].fro)!=getfa(a[i].to)){ 54 unio(a[i].fro,a[i].to); 55 ans+=a[i].val; 56 } 57 } 58 cout<<ans<<endl; 59 }

【Usaco2008 Oct】灌水 (最小生成樹)