第26章 最大流(正在修改)

一、综述

1.定义

定义1:流网络

定义2:残留容量

定义3:增广路径

已知一个网络流G=(V,E)和流f,增广路径p为残留网络G|f中从s到t的一条简单路径

能够沿一条增广路径p的每条边传输的网络流的最大量为p的残留容量,由下式定义:

c|f(p) = min{c|f(u,v) : (u,v)在p上}

定义4:割、净流、容量、最小割

净流和容量的区别:

穿过(S,T)的净流由双向的正网络流组成;在加上从S到T的正网络流的同时,减去从T到S的正网络流。

割(S,T)的容量仅由从S到T的连计算而得。从T到S的边在计算c(S,T)时是不算在内的。

2.性质

3.定理

定理1:

定理2:

定理3:

定理4:

定理5:

定理6:

对一个网络流G中任意流f来说,其值的上界面为G的任意割的容量

定理7:

二、代码

版本一:最大流,图用矩阵实现,求增广路径用BELLMAN-FORD实现

1.Mat_Flow.h
#include <iostream>
using namespace std;

#define NMAX 210

class Mat_Flow
{
public:
    int n;//点的个数。其中0是源点,1是汇点
    int map[NMAX][NMAX];//网络费用
    int net[NMAX][NMAX];//剩余网络
    int path[NMAX];//增广路径,path[v]=u说明(u,v)在增广路径上
    int ecost[NMAX];//源点到各点的最短路径

    Mat_Flow(int num):n(num)
    {
        memset(map, 0, sizeof(map));
    }
    void AddSingleEdge(int start, int end, int value = 1)
    {
        map[start][end] = value;
    }
    void MakeGraph(int m);
    bool bellman_ford();
    int max_flow();
};

void Mat_Flow::MakeGraph(int m)
{
    int start, end, value;
    while(m--)
    {
        cin>>start>>end>>value;
        AddSingleEdge(start, end, value);
    }
}
bool Mat_Flow::bellman_ford()
{
    int i, j;
    memset(path, -1, sizeof(path));
    fill(ecost, ecost+NMAX, INT_MAX);
    ecost[0] = 0;

    bool flag = true;
    while(flag)
    {
        flag = false;
        for(i = 0; i <= n; i++)
        {
            if(ecost[i] == INT_MAX)
                continue;
            for(j = 0; j <= n; j++)
            {
                if(net[i][j] > 0 && ecost[i] + 1 < ecost[j])
                {
                    flag = true;
                    ecost[j] = ecost[i] + 1;
                    path[j] = i;
                }
            }
        }
    }
    return ecost[n] != INT_MAX;
}

int Mat_Flow::max_flow()
{
    int i, j;
    //初始时,剩余网络即为整个网络
    for(i = 0; i <= n; i++)
    {
        for(j = 0; j <= n; j++)
            net[i][j] = map[i][j];
    }
    int maxflow = 0;
    //while there exists a path p from s to t int the residual network G1
    //从剩余网络中找到一条增广路径,增广路径存在在path中
    while(bellman_ford())
    {
        //do c|f(p) <- min {c|f(u,v):(u,v) is in p}
        //计算增广路径上的净流
        int v = n, cfp = INT_MAX, u;
        while(v != 0)
        {
            //path存储的是增广路径,path[v]=u说明(u,v)在增广路径上
            u = path[v];
            cfp = min(cfp, net[u][v]);
            v = u;
        }
        //更新最大流的大小
        maxflow += cfp;
        //更新剩余网络
        //for each edge(u,v) in p
        v = n;
        while(v != 0)
        {
            u = path[v];
            //f[u,v] <- f[u,v] + cfp
            net[u][v] -= cfp;
            net[v][u] += cfp;
            //f[v,u] <- -f[u,v]
            v = u;
        }
    }
    return maxflow;
}

2.main.cpp

#include "Mat_flow.h"
/*
5 10
0 1 16
0 2 13
1 3 12
1 2 10
2 1 4
3 2 9
2 4 14
3 5 20
4 3 7
4 5 4
*/
int main()
{
    int n, m;
    while(cin>>n>>m)
    {
        Mat_Flow *G = new Mat_Flow(n);
        G->MakeGraph(m);
        cout<<G->max_flow()<<endl;
        delete G;
    }
    return 0;
}
3.测试数据

《算法导论》P405图26-5

4.运行结果

版本2:矩阵+HLPP(高度标号预流推进算法)

1."Mat_HLPP_Flow.h"

http://my.csdn.net/my/code/detail/50632

2.main.cpp
#include "Mat_HLPP_Flow.h"
/*
5 10
0 1 16
0 2 13
1 3 12
1 2 10
2 1 4
3 2 9
2 4 14
3 5 20
4 3 7
4 5 4
*/
int main()
{
    int n, m;
    while(cin>>n>>m)
    {
        Mat_HLPP_Flow *G = new Mat_HLPP_Flow(n);
        G->MakeGraph(m);
        cout<<G->high_label_preflow_push()<<endl;
        delete G;
    }
    return 0;
}
3.测试数据与测试结果

同上

三、练习

26.1 网络流

26.1-1

定义1:如果(u,v)不属于E,c(u,v)=0
性质1:f(u,v) <= c(u,v)
====> 如果(u,v)不属于E,f(u,v) = 0。
反向边同理

26.1-2
性质2,反对称性
26.1-3
待解决
26.1-4

26.1-5

(1)f(X,Y)=-f(V-X,Y)
X:t   Y:v3,v4
(2)f(X,Y)!=-f(V-X,Y)
X:v3,v4  Y:v1,v2

26.1-6
必定满足“反对称性”和“流守恒性”,可能违反“容量限制”
26.1-7

由26.1-6知,af1+(1-a)f2满足“反对称性”和“流守恒性”。
因为f1和f2满足“容量限制”,因此af1+(1-a)f2满足“容量限制”
所以af1+(1-a)f2也是流

26.1-8
在网络中每一节点流入流出的量应该相等

无标题 

例如上图,可以写出以下等式:

x1 – x3 –x4 = 0

x2 + x3 – x5 = 0
26.1-9

将地图转换为一个有向图:
(1)每个角落作为一个顶点
(2)若一个角落到另一个角落有路,则构成有向图的边。
(3)每条路构成正向和反向两条边,容量都是1
计算该有向图的最大流,若最大流大于或等于2,则“可以”

26.2Ford-Fulkerson方法

26.2-1

净流:19

容量:31

26.2-2

IMG_3679

 


26.2-3
最大流的最小割是23
第二条增广路径的第二段和第三条增广路径的第2段抵消
第一条增广路径的第三段和第四条增广路径的第2段抵消
26.2-4
根据反对称性和残留网络定义
    c|f(u,v) + c|f(v,u)
 =    c(u,v) - f(u,v) + c(v,u) - f(v,u)
 =    c(u,v) + c(v,u)
 26.2-5
根据流守恒

26.2-6

 IMG_3678

26.2-7

似乎是很显然的事情

26.2-8

不知道题目是什么意思,讨厌证明题

26.2-9

构造这样一个带权有向图G2,

G2的顶点和G是一样的。若G中存在一条(u,v)的边,则在G2中加一条u->v的边,和一条v->u的边,权值都是1.

在G2的基础上构造|V|个网络流,依次令|V|个顶点分别做为汇点,再选一个不是汇点的点做为源点。依次求这|V|个网络流的最大流。

这|V|个网络流的最小值即为G的边连通度

26.3最大二分匹配

26.3-1

IMG_3680

26.3-2

又见证明题

26.3-3

2*min(|L|, |R|)+1

26.4 压入与重标记法

26.5重标记与前移算法

四、思考题

26-1逃脱问题

(1)构造网络流G,令m个点为G的源点,令边界点中不是源点的点为G的汇点。

(2)若两个顶点相邻,则构造两条有向边,边权为1

26-2最小路径覆盖

26-3航天飞机实验

26-4最大流的更新
26-5用定标法计算最大流

26-6具有负容量的最大流

26-7Hopcroft-Karp二分图匹配算法

posted @ 2014-06-13 20:54  windmissing  阅读(603)  评论(0编辑  收藏  举报