最大流问题

最大流问题比较好理解,就是给出一个图,每条边有限制的最大容量,要求从起始节点输出到结束节点,所有中间节点的输入与输出相等,求一条能带来最大流量的路径。
这里,我们直接讲解比较成熟的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);

    }



}

测试用例:
例子
输入:

6
0 5
0 16 13 0 0 0
0 0 0 12 0 0
0 4 0 0 14 0
0 0 9 0 0 20
0 0 0 7 0 4
0 0 0 0 0 0

输出:

最大流为:23
0/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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值