取水问题
Posted liqiniuniu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了取水问题相关的知识,希望对你有一定的参考价值。
http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1213
Famer John希望把水源引入他的N (1 <= N <= 300)个牧场,牧场的编号是1~N。他将水源引入某个牧场的方法有两个,一个是在牧场中打一口井,另一个是将这个牧场与另一个已经有水源的牧场用一根管道相连。在牧场i中打井的费用是W_i (1 <= W_i <= 100000)。把牧场i和j用一根管道相连的费用是P_ij (1 <= P_ij <= 100000, P_ij = P_ji, P_ii = 0)。请你求出Farmer John最少要花多少钱才能够让他的所有牧场都有水源。
解法一:
先每个地方都修一个水井。
将所有的无向边从小到大排序,按照最小生成树的思路,试着将边加入。比如有边edge[i][j]将点i和点j连通,如果修路的费用edge[i][j]小于修水井 i 的费用或者小于修水井 j 的费用,则可以加入这条边,然后可以去掉水井 i 和水井 j 中费用最大的那个。
1 #include<iostream> 2 #include<vector> 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<set> 6 #include<string> 7 #include<algorithm> 8 using namespace std; 9 10 int ans = 0; 11 12 int father[305]; 13 int cost1[305]; 14 int cost2[305][305]; 15 int n; 16 struct road{ 17 int i, j, cost; 18 road(int a, int b, int c){ 19 i = a, j = b, cost = c; 20 } 21 bool operator<(const struct road &other)const{ 22 return cost < other.cost; 23 } 24 }; 25 int find(int i){ 26 if(father[i] != i) father[i] = find(father[i]); 27 return father[i]; 28 } 29 void union_(int i, int j){ 30 int fi = find(i), fj = find(j); 31 if(fi == fj) return ; 32 if(cost2[i][j] > max(cost1[fi], cost1[fj])) return ; 33 if(cost1[fi] < cost1[fj]){ 34 father[fj] = fi, ans = ans - cost1[fj] + cost2[i][j]; 35 }else{ 36 father[fi] = fj, ans = ans - cost1[fi] + cost2[i][j]; 37 } 38 } 39 vector<struct road> roads; 40 int main(){ 41 cin>>n; 42 for(int i = 0; i < n; i++){ 43 father[i] = i; 44 cin>>cost1[i]; 45 ans += cost1[i]; 46 } 47 for(int i = 0; i < n; i++){ 48 for(int j = 0; j < n; j++){ 49 cin>>cost2[i][j]; 50 } 51 } 52 for(int i = 0; i < n; i++){ 53 for(int j = i + 1; j < n; j++){ 54 struct road temp(i, j, cost2[i][j]); 55 roads.push_back(temp); 56 } 57 } 58 sort(roads.begin(), roads.end()); 59 for(int i = 0; i < roads.size(); i++){ 60 union_(roads[i].i, roads[i].j); 61 } 62 cout<<ans; 63 return 0; 64 }
解法二:
设立一个虚拟点n,这个点免费提供水源。
在点 i 修水井的钱,可以看做是从 i 到 n修路的钱。
那么这样的话,可以看做将点0到点n构造一棵最小生成树。
1 #include<iostream> 2 #include<vector> 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<set> 6 #include<string> 7 #include<algorithm> 8 using namespace std; 9 10 int ans = 0; 11 12 int father[305]; 13 int cost1[305]; 14 int cost2[305][305]; 15 int n; 16 struct road{ 17 int i, j, cost; 18 road(int a, int b, int c){ 19 i = a, j = b, cost = c; 20 } 21 bool operator<(const struct road &other)const{ 22 return cost < other.cost; 23 } 24 }; 25 int find(int i){ 26 if(father[i] != i) father[i] = find(father[i]); 27 return father[i]; 28 } 29 void union_(int i, int j, int cost){ 30 int fi = find(i), fj = find(j); 31 if(fi == fj) return ; 32 father[fi] = fj, ans = ans + cost; 33 } 34 vector<struct road> roads; 35 int main(){ 36 cin>>n; 37 father[n] = n; 38 for(int i = 0; i < n; i++){ 39 father[i] = i; 40 cin>>cost1[i]; 41 struct road temp(i, n, cost1[i]); 42 roads.push_back(temp); 43 } 44 for(int i = 0; i < n; i++){ 45 for(int j = 0; j < n; j++){ 46 cin>>cost2[i][j]; 47 } 48 } 49 for(int i = 0; i < n; i++){ 50 for(int j = i + 1; j < n; j++){ 51 struct road temp(i, j, cost2[i][j]); 52 roads.push_back(temp); 53 } 54 } 55 sort(roads.begin(), roads.end()); 56 for(int i = 0; i < roads.size(); i++){ 57 union_(roads[i].i, roads[i].j, roads[i].cost); 58 } 59 cout<<ans; 60 return 0; 61 }
以上是关于取水问题的主要内容,如果未能解决你的问题,请参考以下文章
水资源税取水计量监管系统 取用水户水量在线监测平台 水资源远程实时监控管理系统
已知有n个羊村村民正在排队取水,懒羊羊不知道他在队伍的具体哪个位置,但他知道有不少于a个人在他前面,有不多于b个人在他后面,你能帮忙计算一下懒羊羊有多少个可能的位置吗?