Drainage Ditches(网络最大流)

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. 

Input

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.

Output

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

Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

Sample Output

50

题意:图论书P270:Joho在农场修建了一套排水系统,并且在每条排水沟的起点安装了调节阀门。这样他就可以控制流入排水沟的水流速度了。已知每条排水后排水沟的方向u->v,以及每条排水沟的最大速度c。求此排水沟的最大流水速度,起点(1)为农场,终点(n)为池塘。

思路:网络流的入门题。我们用结构体储存每一条边的容量c以及最大流量,通过bfs我们找到一条从起点到终点的链,然后在链上找到最大增改值,然后修改结构体的f,重复操作。。。Orz。。。代码上有详细的注释!

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 210
#define inf 0x3f3f3f3f
using namespace std;
struct node  //G(u,v)
{
    int c,f;
} Edge[MAXN][MAXN];

int M,N; 
int s,t;//起点,终点

int residual[MAXN][MAXN];//残留网络
int pre[MAXN];  //链
int vis[MAXN];  //标记

int maxflow,min_augment; //最大流,可增进量

void find_augment_path()
{
    memset(vis,0,sizeof(vis));  //标记清空
    memset(pre,0,sizeof(pre));  //链清空
    memset(residual,0,sizeof(residual)); //残留容量清空
    queue<int>Q;  
    Q.push(s);  //链的第一个为起点 s
    vis[s]=1;   //标记s
    while(!Q.empty()&&!pre[t])  //队列不为空,并且没有到达终点 t
    {
        int cu=Q.front();  //取队首,
        Q.pop();
        for(int i=1; i<=N; i++)  //遍历所有的点
        {
            if(!vis[i])  //如果这个点没有被用过
            {
                if(Edge[cu][i].c - Edge[cu][i].f > 0)  //前向弧 c(u,v) > f(u,v)
                {
                    residual[cu][i] = Edge[cu][i].c - Edge[cu][i].f;//残留网络
                    pre[i]=cu,vis[i]=1,Q.push(i); //扩展链,入队列,标记
                }
                else if(Edge[i][cu].f > 0)  //后向弧  f(u,v) > 0
                {
                    residual[cu][i] = Edge[i][cu].f; //虽然是后向弧,但残留网络要按前向弧计算
                    pre[i]=cu,vis[i]=1,Q.push(i);  //扩展链,入队列,标记
                }
            }
        }
    }
}

void augment_flow() //寻找可增改量,即链中的最小值
{
    int i=t,j=inf;//i为终点,从终点开始找
    if(!pre[i])  //如果扩展的条链没有找到终点
    {
        min_augment = 0; //那么可增改量就是 0
        return;
    }
    while(i!=s) //因为是从起点 s 开始找的,所有 s 为查找终点 
    {
        /*
            因为bfs的时候是倒序储存的(pre[i] = cu ...)
            即 residual(u,v)   此时 v = i,  u = pre[i];
        */
        if(residual[pre[i]][i] < j)  //找这条链中的最小值
            j=residual[pre[i]][i];
        i=pre[i];  //迭代维护 i
    }
    min_augment = j; //可增改量就是 j
}

void update_flow() //更新 f(u,v)
{
    int i=t;
    if(!pre[i])return;//终点没有被找到
    
    while(i!=s)//和上述 augment_flow() 查找方式一样
    {
        if(Edge[pre[i]][i].c-Edge[pre[i]][i].f > 0) //前向弧
            Edge[pre[i]][i].f+=min_augment;  //f(u,v) += min_augment
        else if(Edge[i][pre[i]].f > 0)              //后向弧
            Edge[pre[i]][i].f+=min_augment;  //f(u,v) += min_augment
        i=pre[i];  //迭代维护
    }
}

void solve()
{
    s=1,t=N;//起点,终点
    maxflow = 0; //最大流初始化为 0
    while(1)  //一直循环
    {
        find_augment_path();//先用bfs找增广路
        augment_flow();     //在链中找 可增进量
        maxflow+=min_augment;  //最大流 + 改增进量
        if(min_augment > 0)  //如果存在增进量,就要更新 f(u,v) 了
            update_flow();
        else                 //否则的话,说明已经不存在增广路了,直接退出即可
            break;
    }
}
int main()
{
    int u,v,c;
    while(~scanf("%d%d",&M,&N))
    {
        memset(Edge,0,sizeof(Edge));
        for(int i=0; i<M; i++)
        {
            scanf("%d%d%d",&u,&v,&c);  //起点,终点,容量
            Edge[u][v].c+=c;     //累计容量
        }
        solve();
        printf("%d\n",maxflow);//输出最大流
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41890797/article/details/85231838