zoukankan      html  css  js  c++  java
  • 最大流问题

                          最大流问题

          设一个赋权有向图D=(V, E),在V中指定一个发点vs和一个收点vt ,其它的点叫做中间点。对于D中的每一个弧(vi , vj)∈ E ,都有一个非负数 cij ,叫做弧的容量。我们把这样的图D叫做一个容量网络,简称网络,记做D=(V,E,C)。

    流,即加在网络各条弧上的一组负载量。

    例如:

      如图,在这个运输网络中,源点S和汇点T分别是1,7,各边的容量为C(u,v)。图中红色虚线所示就是一个可行流。

    残余网络 增广路径 反向弧

      —————————>    

                                                                                                      残余网络

           也许现在你已经知道什么是残余网络了,对于已经找到一条从S T的路径的网络中,只要在这条路径上,把 C(u,v) 的值更新为C(u,v) - P(u,v),并且添加反向弧 C(v,u)。对应的增广路径 Path 为残留网络上从ST的一条简单路径。例如:原图1247就是一条增广路径,当然还有1347

    此外在未做任何操作之前,原始的有向图也是一个残余网络,它仅仅是未做任何更新而已。

    最大流定理如果残留网络上找不到增广路径,则当前流为最大流;反之,如果当前流不为最大流,则一定有增广路径。

    Ford-Fulkerson方法

        用Ford-Fulkerson方法求最大流。为什么叫Ford-Fulkerson方法而不是算法,原因在于可以用多种方式实现这一方法,方式并不唯一。下面介绍一种基于广度优先搜索(BFS)来计算增广路径P的算法:Edmonds-Karp算法。

      算法流程如下:

      设队列Q:存储当前未访问的节点,队首节点出队后,成为已检查的标点;

      Path数组:存储当前已访问过的节点的增广路径;

      Flow数组:存储一次BFS遍历之后流的可改进量;

      Repeat:

        Path清空;

        源点S进入PathQPath[S]<-0Flow[S]<-+∞;

        While Q非空 and 汇点T未访问 do

            Begin

                队首顶点u出对;

                For每一条从u出发的弧(u,v) do

                    If v未访问 and (u,v) 的流量可改进;

                    Then Flow[v]<-min(Flow[u],c[u][v]) and v入队 and Path[v]<-u

        End while

       

         If(汇点T已访问)

         Then 从汇点T沿着Path构造残余网络;

      Until 汇点T未被访问

     应该举例

    入门题:http://poj.org/problem?id=1273

    Description

    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

     code:

    #include <cstdio>
    #include <queue>
    #include <memory.h>
    const int M  = 210;
    const int INF = 0x7fffffff;
    int E, V, map[M][M], flow[M], path[M], maxFlow;
    int start, end; // 源点和汇点 
    std::queue<int> qu;
    
    //  BFS求出最短的增广路径 
    int bfs(){
    	int u , v;
    	while(!qu.empty()) qu.pop();
    	memset(path, -1, sizeof(path));
    	path[start] = 0;flow[start] = INF;
    	qu.push(start);
    	while(!qu.empty()){
    		u = qu.front();
    		qu.pop();
    		if(u == end) break;
    		for(v = 1; v <= V; ++v){
    			if(path[v] == -1 && map[u][v]){
    				qu.push(v);
    				path[v] = u;
    				flow[v] = flow[u] < map[u][v] ? flow[u] : map[u][v];
    			}
    		}
    	}
    	if(path[end] == -1) return -1;
    	return flow[V]; // 一次遍历之后的流量增量
    }
    
    void edmonds_karp(){
    	int step, pre, cur;
    	while((step = bfs()) != -1){
    		maxFlow += step;
    		cur = end;
    		while(cur != start){
    			pre = path[cur];
    			map[pre][cur] -= step; // 更新正向边的实际容量
    			map[cur][pre] += step; // 添加反向边
    			cur = pre;
    		}
    	}
    }
    int main(){
    	int k, u, v, c;
    	while(scanf("%d%d", &E, &V) != EOF){
    		memset(map, 0, sizeof(map));
    		for(k = 0; k < E; ++k){
    			scanf("%d%d%d", &u, &v, &c);
    			map[u][v] += c;
    		}
    		start = 1, end = V;       //设定:源点和汇点
    		maxFlow = 0;
    		if(V == 1) printf("INF
    ");
    		edmonds_karp();
    		printf("%d
    ", maxFlow);
    	}
    	return 0;
    }
    
  • 相关阅读:
    测试篇 尝了一下net5.0桌面开发
    日志篇 vs的文本替换,剔除引号保留数字 将vs2019更新之后无法用ctrl+d
    测试篇 使用 nuget.exe CLI 创建 nuget 包
    日志篇 博客园的下方的女孩透明的,带点击声音的
    测试篇 c#文件类型关联启动程序
    数学篇 求两条直线的交点,说明过程.
    日志篇 原生git笔记
    测试篇 winform Anchor 怎么临时取消关联,窗口边界和控件关联
    cad.net dll动态加载,插件式架构,在dll查找引用了的dll,查找dll依赖,dll热插拔,加载dll运行出错.
    cad.net 图元反应器,图元事件,要加在提交数据库之后哟
  • 原文地址:https://www.cnblogs.com/liyangguang1988/p/3660421.html
Copyright © 2011-2022 走看看