最大流问题

来源:互联网 发布:php重庆好找工作吗 编辑:程序博客网 时间:2024/05/29 08:55

最大流问题比较好理解,就是给出一个图,每条边有限制的最大容量,要求从起始节点输出到结束节点,所有中间节点的输入与输出相等,求一条能带来最大流量的路径。
这里,我们直接讲解比较成熟的Ford-Fulkerson算法,在求增广路径时,我们采用的是广度优先搜索。效率可达O(VE^2)。

算法步骤:
1.输入数据,作为图G的边及边的容量;
2.跟据图G,通过广度优先搜索,选出一条从起始节点到结束节点的路径path,并记录路径中的流大小(即流量最小的段的流量);
3.根据图G与path构造图Gf:Gf每条边有容量当前流量两个数据,容量即为图G的容量,流量即为路径path的流量;
4.根据图Gf构造新的图G:对于Gf中的边(u,v),流量/容量 为 m/n,则在Gf中构造两条边,分别为边(u,v),容量 = n - m ; 边(v,u),容量 = m
5.同第2步;
6.根据得到的path,更新图Gf;
7.重复4,5,6步,直到不再有新的增广路径path产生;
8.输出结果。

具体代码:

import java.util.ArrayList;import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;/** *  * @author Founder * 输入方式:采用矩阵输入法,第一行输入节点个数,第二行输入源节点与终节点编号,后面的行输入矩阵 * */public class Main{    public static void main(String[] args){        G g = initialize();        Gf gf = new Gf(g);        while(!gf.isEnd()){            g = new G(gf);            gf.setFlowByPath(g.getPath());        }        print(gf);      }    private static G initialize(){        Scanner input = new Scanner(System.in);        int n = input.nextInt();        G g = new G(n,input.nextInt(),input.nextInt());        int[][] matrix = g.getMatrix();        for(int i = 0; i < n; ++i)            for(int j = 0; j < n; ++j)                matrix[i][j] = input.nextInt();        return g;    }    private static void print(Gf gf){        System.out.println("最大流为:" + gf.getFlowAmount());        int[][] flow = gf.getFlow();        int[][] capacity = gf.getCapacity();        for(int m = 0; m < flow.length; ++m){            for(int n = 0; n < flow.length; ++n)                System.out.print(flow[m][n] + "/" + capacity[m][n] + " ");            System.out.println();        }    }}class G{    public final static int WHITE = 0;    public final static int GRAY = 1;    public final static int BLACK = 2;    private int[] color;    private int[] parent;    private int[][] matrix;    private int size;    private int source;    private int terminal;    public int[] getColor() {        return color;    }    public void setNodeColor(int position,int color) {        this.color[position] = color;    }    public int getSize() {        return size;    }    public int[][] getMatrix() {        return matrix;    }    public void setMatrix(int[][] matrix) {        this.matrix = matrix;    }    /**     *      * @return path的最后一个数字为path的流量大小     */    public ArrayList<Integer> getPath(){        Queue<Integer> queue = new LinkedList<>();        queue.offer(source);        int current = source;        while(!queue.isEmpty() && current != terminal){            current = queue.poll();            for(int i = 0; i < size; ++i){                if(matrix[current][i] != 0 && color[i] == WHITE){                    queue.offer(i);                    color[i] = GRAY;                    parent[i] = current;                    if( i == terminal){                        current = terminal;                        break;                    }                }            }            color[current] = BLACK;        }        if(current != terminal)            return null;        else{            ArrayList<Integer> path = new ArrayList<>();            int amount = 2000000000;            while(current != source){                path.add(current);                current = parent[current];                int tempAmount = matrix[current][path.get(path.size() - 1)];                amount = amount > tempAmount?tempAmount:amount;            }            path.add(source);            path.add(amount);            return path;        }    }    public int getSource() {        return source;    }    public void setSource(int source) {        this.source = source;    }    public int getTerminal() {        return terminal;    }    public void setTerminal(int terminal) {        this.terminal = terminal;    }    public G(int n,int source,int terminal) {        size = n;        this.source = source;        this.terminal = terminal;        color = new int[n];        parent = new int[n];        for(int i = 0; i < n; ++i){            color[i] = WHITE;            parent[i] = -1;        }        matrix = new int[n][n];    }    public G(Gf gf){        size = gf.getSize();        this.source = gf.getSource();        this.terminal = gf.getTerminal();        color = new int[size];        parent = new int[size];        for(int i = 0; i < size; ++i){            color[i] = WHITE;            parent[i] = -1;        }        matrix = new int[size][size];        int[][] capacity = gf.getCapacity();        int[][] flow = gf.getFlow();        for(int m = 0; m < size; ++m)            for(int n = 0; n < size; ++n){                if(capacity[m][n] != 0){                    matrix[m][n] = capacity[m][n] - flow[m][n];                    matrix[n][m] = flow[m][n];                }            }    }}class Gf{    private int[][] flow;    private int[][] capacity;    private int size;    private int source;    private int terminal;    private int flowAmount = 0;    private boolean isEnd = false;    public int[][] getFlow() {        return flow;    }    public void setFlow(int[][] flow) {        this.flow = flow;    }    public int[][] getCapacity() {        return capacity;    }    public void setCapacity(int[][] capacity) {        this.capacity = capacity;    }    public int getSize() {        return size;    }    public int getSource() {        return source;    }    public void setSource(int source) {        this.source = source;    }    public int getTerminal() {        return terminal;    }    public void setTerminal(int terminal) {        this.terminal = terminal;    }    public int getFlowAmount() {        return flowAmount;    }    public void setFlowAmount(int flowAmount) {        this.flowAmount = flowAmount;    }    public boolean isEnd() {        return isEnd;    }    public void setEnd(boolean isEnd) {        this.isEnd = isEnd;    }    public Gf(int n) {        size = n;        flow = new int[size][size];        capacity = new int[size][size];    }    public Gf(G g) {        size = g.getSize();        this.source = g.getSource();        this.terminal = g.getTerminal();        capacity = g.getMatrix();        flow = new int[size][size];        for(int i = 0; i < size; ++i)            for(int j = 0; j < size; ++j)                flow[i][j] = 0;        setFlowByPath(g.getPath());    }    public void setFlowByPath(ArrayList<Integer> path){        if(path != null){            int amount = path.get(path.size() - 1);            flowAmount += amount;            for(int i = path.size() - 2; i > 0; --i){                int u = path.get(i);                int v = path.get(i - 1);                if(capacity[u][v] == 0)                    flow[v][u] -= amount;                else                    flow[u][v] += amount;            }        }else            setEnd(true);    }}

测试用例:
例子
输入:

60 50 16 13 0 0 00 0 0 12 0 00 4 0 0 14 00 0 9 0 0 200 0 0 7 0 40 0 0 0 0 0

输出:

最大流为:230/0 12/16 11/13 0/0 0/0 0/0 0/0 0/0 0/0 12/12 0/0 0/0 0/0 0/4 0/0 0/0 11/14 0/0 0/0 0/0 0/9 0/0 0/0 19/20 0/0 0/0 0/0 7/7 0/0 4/4 0/0 0/0 0/0 0/0 0/0 0/0 
0 0