BZOJ 1601 [Usaco2008 Oct]灌水:最小生成树
题目链接: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 return a.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 }