OPENJUDGE 1273 DRAINAGE DITCHES

来源:互联网 发布:php上传图片缩略图 编辑:程序博客网 时间:2024/06/06 13:57
时间限制: 
1000ms 
内存限制: 
65536kB
描述
Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch. 
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network. 
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle. 
输入
The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
输出

For each case, output a single integer, the maximum rate at which water may emptied from the pond.


下面提供programming.girds.cn上的中文翻译:

描述每次降雨落在农民约翰的田里,贝茜最喜欢的三叶草田就会被淹没而形成一个池塘。下雨总是意味着三叶草久久地长眠水下,田地需要经过很长时间才能露出水面。因此,农民约翰建了一套排水沟系统,这样贝茜的三叶草田就永远不会被水淹没,他就能永远看到贝茜的微笑了。在约翰的计划里,这些水将会被抽到一个附近的河流里。作为一个工程师,农民约翰已经在每个排水沟上安装了流量调节的装置,因此,他就可以控制水流流入每条排水沟的速率了。 

农民约翰不仅知道每条排水沟每分钟分别能够输送多少加仑的水,也知道这些排水沟确切的排布。排水沟间可能有交汇的地方,形成一个节点,这套系统会是一个复杂的网络。 

给定了这些信息,请确定这套系统每分钟把水从池塘输送到附近的河流的最大速率。对于每一条的排水沟,水流总是朝一个方向流的,但是不排除出现沿着某个由排水沟组成的回路,水流能够流一圈而形成一个环。 

关于输入包含多组输入。对于每一组输入,第1行包含两个由空格隔开的整数,N (0 <= N <= 200)和M (2 <= M <= 200)。N是农民约翰挖的排水沟的数量。M是排水沟之间的交汇点的数量。1号交汇点就是池塘,M号交汇点就是附近的那条小河。接下来的N行每一行都包含3个整数,Si,Ei和Ci。Si和Ei (1 <= Si, Ei <= M)是两个交汇点,这条排水沟是从Si流向Ei。Ci (0 <= Ci <= 10,000,000)是这条排水沟容许的最大流量(它是由排水沟本身的宽度深度等决定的)。 
关于输出对于每一组的输入数据,输出一个整数,即这个网络从池塘向河流输送水的最大速率。
例子输入
5 41 2 401 4 202 4 202 3 303 4 10
例子输出
50
提示基础的最大流问题

基础的最大流问题。重点在于使用BFS提高增广路径的检索效率,限制路径搜索次数。直接采用FORD-FULKERSON算法框架。坑爹的是,本题允许两点之间存在多条同向边,所以应该注意两点间的CAPACITY是所有边CAPACITY之和


代码:

# include <iostream># include <queue># include <vector># include <list># define INFINITY 999999999using namespace std;class FlowNetwork{int ** capacityMatrix;int ** flowMatrix;int ** residualNetwork;vector<bool> residualTag;//Visit Tag For The Residual Networklist<pair<int,int> > augmentPath; //Storage for the augmenting path;int verticesNum;public:FlowNetwork(int verticesNum_){int i = 0;int j = 0;capacityMatrix = new int*[verticesNum_+1];flowMatrix = new int*[verticesNum_+1];residualNetwork = new int*[verticesNum_+1];for ( i = 0; i <= verticesNum_; i++ ){capacityMatrix[i] = new int[verticesNum_+1];flowMatrix[i] = new int[verticesNum_+1];residualNetwork[i] = new int[verticesNum_+1];}for ( i = 0; i <= verticesNum_; i++ ){for ( j = 0; j <= verticesNum_; j++ ){capacityMatrix[i][j] = 0;flowMatrix[i][j] = 0;residualNetwork[i][j] = 0;}residualTag.push_back(false);}verticesNum = verticesNum_;}void getInput(int n){int from = 0;int to = 0;int weight = 0;for ( int i = 0; i < n; i++ ){cin >> from >> to >> weight;capacityMatrix[from][to] += weight;}}//按增广路径扩流后重置剩余网络void resetResidual(){augmentPath.clear();int j = 0;for ( int i = 1; i <= verticesNum; i++ ){residualTag[i] = false;for ( j = 1; j <= verticesNum; j++ ){residualNetwork[i][j] = capacityMatrix[i][j] - flowMatrix[i][j];}}}//宽度优先找增广路径并记录于augmentPath,找到返回truebool findPath(){vector<int> father(verticesNum+1,0);//记录节点的父节点用以反推路径queue<int> q;int start = 1;int end = 1;q.push(start);while ( start != verticesNum && !q.empty())//while the queue is not empty and the terminal unreached{start = q.front();q.pop();for ( end = 1; end <= verticesNum; end++ ){if ( residualNetwork[start][end] > 0 && residualTag[end] == false )//There is an unvisited node in the residual network{q.push(end);residualTag[end] = true;father[end] = start;}}}if ( start == verticesNum ){int p = verticesNum;while ( p != 1 && p != 0 )//当p不是源点时逆推路径{augmentPath.push_back(make_pair(father[p],p));p = father[p];}return true;}else return false;}//找到augmentPath的最小容量int min_PathCapacity(){int min = INFINITY;list<pair<int,int> >::iterator i;for ( i = augmentPath.begin(); i != augmentPath.end(); i++ ){if ( residualNetwork[i->first][i->second] < min ){min = residualNetwork[i->first][i->second];}}return min;}//扩流void flowUp(){int pathCapacity = min_PathCapacity();list<pair<int,int> >::iterator i;for ( i = augmentPath.begin(); i != augmentPath.end(); i++ ){flowMatrix[i->first][i->second] += pathCapacity;flowMatrix[i->second][i->first] = -flowMatrix[i->first][i->second];}}void getMaxFlow(){int sum = 0;for ( int i = 2; i <= verticesNum; i++ ){sum += flowMatrix[1][i];}cout << sum << endl;}};int main(){int N = 0;int M = 0;while( cin >> N >> M ){FlowNetwork flow(M);flow.getInput(N);flow.resetResidual();while ( flow.findPath() ){flow.flowUp();flow.resetResidual();}flow.getMaxFlow();}return 0;}