最大流算法

一、网络流模型

1.1 网络流定义

一个流量网络是一张边的权重(这里称为容量)为正的加权有向图。该网络中通常有一个起点s和一个终点t,从起点s出发到达终点t的每一条边都有一个流量上限值(容量),网络流问题就是找到各种流量配置方案,使得每一条边的实际流量小于容量且每个顶点(除s、t)的净流量为0。

术语:
流入量:流向一个顶点的总流量(所有指向该顶点的边中的流量之和)
流出量:流出一个顶点的总流量(由该顶点指出的所有边中的流量之和)
净流量:流入量 - 流出量
最大s-t流量:给定一个s-t流量网络,找到一种流量配置方案,使得s->t的流量最大化

如下是用加权有向图表示网络流问题的模型:

1.2 API定义

流量边的API:

1-2-1 流量网络中边的API

流量边-源码:

public class FlowEdge {
    private final int v; // from
    private final int w; // to
    private final double capacity; // 容量
    private double flow; // 实际流量: v -> w
 
    public FlowEdge(int v, int w, double capacity) {
        if (capacity < 0.0)
            throw new IllegalArgumentException("Edge capacity must be non-negative");
        this.v = v;
        this.w = w;
        this.capacity = capacity;
        this.flow = 0.0;
    }
 
    public int from() {
        return v;
    }
 
    public int to() {
        return w;
    }
 
    public double capacity() {
        return capacity;
    }
 
    public double flow() {
        return flow;
    }
 
    public int other(int vertex) {
        if (vertex == v)
            return w;
        else if (vertex == w)
            return v;
        else
            throw new IllegalArgumentException("invalid endpoint");
    }
 
    /**
     * 返回边的流量
     * 
     * @return 如果顶点vertex是该边的起始顶点,返回边的实际流量
     *         如果顶点vertex是该边的结束顶点,返回边的剩余流量
     */
    public double residualCapacityTo(int vertex) {
        if (vertex == v)
            return flow; // backward edge
        else if (vertex == w)
            return capacity - flow; // forward edge
        else
            throw new IllegalArgumentException("invalid endpoint");
    }
 
    /**
     * 增加/减少边的流量
     * 如果顶点vertex是该边的起始顶点,则减少边的流量
     * 如果顶点vertex是该边的结束顶点,则增加边的流量
     */
    public void addResidualFlowTo(int vertex, double delta) {
        if (delta < 0.0)
            throw new IllegalArgumentException("Delta must be nonnegative");
 
        if (vertex == v)
            flow -= delta; // backward edge
        else if (vertex == w)
            flow += delta; // forward edge
        else
            throw new IllegalArgumentException("invalid endpoint");
 
        if (flow < 0.0)
            throw new IllegalArgumentException("Flow is negative");
        if (flow > capacity)
            throw new IllegalArgumentException("Flow exceeds capacity");
    }
 
    public String toString() {
        return v + "->" + w + " " + flow + "/" + capacity;
    }
}

流量网络的API:

1-2-2 流量网络API
1-2-3 流量网络示意图

流量网络的源码:

public class FlowNetwork {
    private final int V; // 顶点数
    private int E; // 边数
    private Bag<FlowEdge>[] adj; // adj[v]表示顶点v的所有出边
 
    public FlowNetwork(int V) {
        if (V < 0)
            throw new IllegalArgumentException("Number of vertices in a Graph must be nonnegative");
        this.V = V;
        this.E = 0;
        adj = (Bag<FlowEdge>[]) new Bag[V];
        for (int v = 0; v < V; v++)
            adj[v] = new Bag<FlowEdge>();
    }
    public FlowNetwork(In in) {
        int V = in.readInt();
        this(V);
        int E = in.readInt();
        if (E < 0)
            throw new IllegalArgumentException("number of edges must be nonnegative");
        for (int i = 0; i < E; i++) {
            int v = in.readInt(); // 起始顶点
            int w = in.readInt(); // 结束顶点
            double capacity = in.readDouble(); // 容量
            addEdge(new FlowEdge(v, w, capacity));
        }
    }
 
    public int V() {
        return V;
    }
    public int E() {
        return E;
    }
    public void addEdge(FlowEdge e) {
        int v = e.from();
        int w = e.to();
        adj[v].add(e);
        adj[w].add(e);
        E++;
    }
    public Iterable<FlowEdge> adj(int v) {
        return adj[v];
    }
 
    // return list of all edges - excludes self loops
    public Iterable<FlowEdge> edges() {
        Bag<FlowEdge> list = new Bag<FlowEdge>();
        for (int v = 0; v < V; v++)
            for (FlowEdge e : adj(v)) {    //只保存顶点v的出边
                if (e.to() != v)
                    list.add(e);
            }
        return list;
    }
 
    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append(V + " " + E + "\n");
        for (int v = 0; v < V; v++) {
            s.append(v + ":  ");
            for (FlowEdge e : adj[v]) {
                if (e.to() != v)
                    s.append(e + "  ");
            }
            s.append("\n");
        }
        return s.toString();
    }
}

二、最大流算法

2.1 Ford-Fulkerson算法

2.1.1 定义

Ford - Fulkerson 最大流量算法,网络中的初始流量为零,沿着任意从起点到终点(且不含有饱和的正向边或空逆向边)的增广路增大流量,直到网络中不存在这样的路径为止。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容