BZOJ 1601 [Usaco2008 Oct]灌水:最小生成樹
阿新 • • 發佈:2017-10-03
ostream opera 兩種方法 數字 {} back 一個 stream print
題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1601
題意:
Farmer John已經決定把水灌到他的n(1<=n<=300)塊農田,農田被數字1到n標記。
把一塊土地進行灌水有兩種方法,從其他農田飲水,或者這塊土地建造水庫。
建造一個水庫需要花費wi(1<=wi<=100000),連接兩塊土地需要花費P[i][j](1 <= p[i][j] <= 100000, p[i][j]=p[j][i], p[i][i]=0)。
計算Farmer John所需的最少代價。
題解:
農田標號1到n,建立超級源點為0號點。
從超級源點向每個農田連一條長度為w[i]的邊。然後n個農田之間再互相連接,邊長為p[i][j]。
然後求最小生成樹就好。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <vector> 6 #define MAX_N 305 7 8 using namespace std; 9 10 struct Edge 11{ 12 int sour; 13 int dest; 14 int len; 15 Edge(int _sour,int _dest,int _len) 16 { 17 sour=_sour; 18 dest=_dest; 19 len=_len; 20 } 21 Edge(){} 22 friend bool operator < (const Edge &a,const Edge &b) 23 { 24 returna.len<b.len; 25 } 26 }; 27 28 int n; 29 int ans; 30 int par[MAX_N]; 31 vector<Edge> edge; 32 33 void init_union_find() 34 { 35 for(int i=0;i<=n;i++) 36 { 37 par[i]=i; 38 } 39 } 40 41 int find(int x) 42 { 43 return par[x]==x?x:par[x]=find(par[x]); 44 } 45 46 void unite(int x,int y) 47 { 48 int px=find(x); 49 int py=find(y); 50 if(px==py) return; 51 par[px]=py; 52 } 53 54 bool same(int x,int y) 55 { 56 return find(x)==find(y); 57 } 58 59 int kruskal() 60 { 61 init_union_find(); 62 sort(edge.begin(),edge.end()); 63 int cnt=0; 64 int res=0; 65 for(int i=0;i<edge.size();i++) 66 { 67 Edge temp=edge[i]; 68 if(!same(temp.sour,temp.dest)) 69 { 70 cnt++; 71 res+=temp.len; 72 unite(temp.sour,temp.dest); 73 } 74 } 75 return cnt==n?res:-1; 76 } 77 78 void read() 79 { 80 cin>>n; 81 int a; 82 for(int i=1;i<=n;i++) 83 { 84 cin>>a; 85 edge.push_back(Edge(0,i,a)); 86 } 87 for(int i=1;i<=n;i++) 88 { 89 for(int j=1;j<=n;j++) 90 { 91 cin>>a; 92 if(i<j) edge.push_back(Edge(i,j,a)); 93 } 94 } 95 } 96 97 void solve() 98 { 99 ans=kruskal(); 100 } 101 102 void print() 103 { 104 cout<<ans<<endl; 105 } 106 107 int main() 108 { 109 read(); 110 solve(); 111 print(); 112 }
BZOJ 1601 [Usaco2008 Oct]灌水:最小生成樹