網絡流(最大流)EK算法

最大流問題:

假設需要把一些物品從節點s(稱爲源點) 運送到節點t(稱爲匯點) 可以從其他點進行中轉,每兩個點之間都有容量的限制,問從s到t,能運送的最大值是多少。

上圖 從 1-4 最大流爲 80 + 50 = 130

劉汝佳白書定義:

對於一條邊(u,v)他的物品上限稱爲容量,記c(u,v)(對於不存在的邊,c(u,v) = 0 );實際運送的物品稱爲流量(flow) 記f(u,v)從u運送到3個物品至v,再從v運送5個物品至u,等價於從v送2個物品至u。可以規定f(u,v) = -f(v,u)

在最大流問題中,容量c與流量f需要滿足3個條件:容量限制(c(u,v) >= f(u,v)),斜對稱性(f(u,v) = -f(v,u)) 和流量平衡(對於除了節點s與t之外的任意節點u  西格瑪\sum\sumf(u,t) = 0,這樣是保證s->t 所有的通路都被佔用,不會再有殘量)即從s的流出淨流量等於t的匯入淨流量。

 

介紹完最大流問題後,我們介紹一下他的最基本的算法:增廣路算法。

這裏需要知道每邊的容量與實際流量之差(稱爲殘量),用殘量構建一個網絡(稱爲殘量網絡(residual network))。例如上述例子的“殘量網絡”爲

但是僅此還不夠,殘量網絡是包含正反兩條邊的,上面的圖只是完成了一半。反邊的畫法就是原來的邊的容量

此圖纔是殘量網絡。

爲什麼要加上反邊呢?

我們來看一個新的案例

對於此網絡,假設有一條路從 1-2-3-4

對於這種情況算出來的最大流就是1,但是我們很容易看出最大流應該是2。我們加上反邊試試

加上反邊後,存在一條路1-3-2-4的綠色路徑

就算我們第一步走的1-2-3-4,之後又會走1-3-2-4 算出的最大流同樣是2.

根據網絡流的斜對稱性 f(u,v) = -f(v,u)可知,我們2-3和3-2的淨流量相當於0。實際上2-3之間的根本沒有流量流過,我們的反邊就是起到這個作用(後悔操作,也就是鬆弛)。。

我們的最大流就是不斷的在殘量網絡中尋找增廣路,並且該增廣路的最大流量應該是該路的最小容量(容量限制法則)。 並且該增廣路同時減去該最小容量,得到一個新的殘量網絡。最後殘量網絡無增廣路(流量平衡原理),得出來的纔是最大流。

 

下面看一道例題:

D - Drainage Ditches

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

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

最大流的模板題,求1-n的最大流

直接看代碼

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#define  LL long long
#define  ULL unsigned long long
#define mod 1000000007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
#define maxn 1000005
using namespace std;
const double eps = 1e-2;
double dp[205];
int n,m;
int capacity[205][205];//殘量網絡
int flow[205];//i的流量
int pre[205];//前驅節點,同時可以起到vis作用
int BFS(int st,int ed)//找增廣路的最大流
{
    queue<int> Q;
    mem(pre,-1);
    pre[st] = 0;
    flow[st] = INF;
    Q.push(st);
    while(!Q.empty()){
      int v = Q.front();
      Q.pop();
      if(v == ed) break;
      for(int i = 1; i <= n; i++){
        if(i != st && capacity[v][i] > 0 && pre[i] == -1){
          pre[i] = v;
          flow[i] = min(capacity[v][i],flow[v]);
          Q.push(i);
        }
      }
    }
    if(pre[ed] == -1) return -1;
    else return flow[ed];

}
int maxFlow(int st,int ed)
{
    int increase = 0;
    int sumflow = 0;
    while((increase = BFS(st,ed)) != -1){//若存在增廣路
      int k = ed;//從匯點像源點反過來找
      while(k != st){
        int last = pre[k];
        capacity[last][k] -= increase;//正向
        capacity[k][last] += increase;//反向
        k = last;
      }
      sumflow += increase;
    }
    return sumflow;
}
int main()
{
    while(~scanf("%d%d",&m,&n)){
      mem(flow,0);
      mem(capacity,0);
      for(int i = 0; i < m; i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(a == b) continue;
        capacity[a][b] += c;//防止重邊出現
      }
      printf("%d\n",maxFlow(1,n));
    }




    return 0;

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章