使用Edmond-Karp算法实现不输出最大流量值

时间:2016-11-03 19:23:54

标签: java algorithm graph matching edmonds-karp

我正在实现一个程序,通过使用从匹配问题的减少到最大流问题来解决匹配问题,我决定使用Edmond-Karp算法解决这个问题。

我已经查看了不同伪代码的印象并告诉我们如何使用Edmond-Karp算法执行解决最大流量问题的过程,并通过混合这些印象,我已经制作了一个适用于许多人的实现小基本图。但由于某种原因,实现为更大的图形提供了错误的答案,例如50个节点,100个边缘甚至比这些图形更大。因此,给出输入输出场景示例对突出显示整个问题没有多大帮助(如果你坚持,我可以按照你的意愿发布这样的输入输出场景)。当我说“错误答案”时,实现实际上并没有给出最大匹配(或最大流量值)给定图表来解决。

在下面你可以拥有我的实现中使用的所有相关类,即MaxFlowSolver类(方法solveFlowProblem(...)是使用整个Edmond-Karp算法的方法):

MaxFlowSolver

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

public class MaxFlowSolver {
    private Graph flowProblemSolution;
    private int flowValue;

    public MaxFlowSolver(Graph toBeSolved, int source, int sink) {
        flowProblemSolution = solveFlowProblem(toBeSolved, source, sink);
    }

    private Graph solveFlowProblem(Graph toSolve, int source, int sink) {
        Graph rGraph = toSolve;
        Edge[] path;

        while((path=BFS(rGraph, source, sink))!=null) {                     
            int r = Integer.MAX_VALUE;
            for(Edge e = path[sink]; e!=null; e = path[e.getStartVertex()])
                r = Math.min(r, e.getCapacity()-e.getFlow());

            for(Edge e = path[sink]; e!=null; e = path[e.getStartVertex()]) {
                e.changeFlow(e.getFlow()+r);
                Edge erev;
                if((erev=getReversedEdge(e, rGraph))==null) {
                    erev = new Edge(e.getEndVertex(), e.getStartVertex(), 0);
                    rGraph.addEdge(erev);
                }
                erev.changeFlow(-e.getFlow());
                e.changeResCap(e.getCapacity()-e.getFlow());
                erev.changeResCap(erev.getCapacity()-erev.getFlow());
            }
            flowValue += r;
        }

        return rGraph;
    }

    private Edge getReversedEdge(Edge e, Graph graph) {
        LinkedList<Edge> neighbours = graph.getEdges().get(e.getEndVertex());
        if(neighbours==null)
            return null;

        for(Edge i : neighbours)
            if(i.getEndVertex()==e.getStartVertex())
                return i;

        return null;
    }

    private Edge[] BFS(Graph resGraph, Integer source, Integer sink) {
        Queue<Integer> q = new LinkedList<>();
        q.add(source);
        Edge[] pred = new Edge[resGraph.numVertices()+1];

        while(!q.isEmpty()) {
            Integer curr = q.poll();
            LinkedList<Edge> neighbours1 = resGraph.getEdges().get(curr);

            if(neighbours1!=null)
                for(Edge someEdge : neighbours1) {
                    if(pred[someEdge.getEndVertex()]==null && someEdge.getEndVertex()!=source && 
                            someEdge.getCapacity()>someEdge.getFlow()) {
                        pred[someEdge.getEndVertex()] = someEdge;
                        q.add(someEdge.getEndVertex());
                    }
                }

            if(curr==sink) return pred;
        }

        return null;
    }

    public Graph getSolution() {
        return flowProblemSolution;
    }

    public ArrayList<Edge> retrievePositiveEdges(Graph arg0, int source, int sink) {
        ArrayList<Edge> res = new ArrayList<>();
        Set<Integer> goThroughInts = flowProblemSolution.getEdges().keySet();

        for(Integer i : goThroughInts)
            for(Edge j : flowProblemSolution.getEdges().get(i)) {
                int start = j.getStartVertex();
                int end = j.getEndVertex();
                if(!res.contains(j) && j.getFlow()>0 && 
                        start!=source && start!=sink && end!=source && end!=sink && 
                        arg0.getEdges().get(i).contains(j))
                    res.add(j);
            }

        return res;
    }

    public int getFlowValue() {
        return flowValue;
    }
}

图形

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;

    public class Graph {    
        private HashMap<Integer, LinkedList<Edge>> edges;
        private int firstVertices;
        private int secondVertices;
        private int size;

        public Graph(int x, int y) {
            firstVertices = x;
            secondVertices = y;
            edges = new HashMap<>();
            size = 0;
        }

        public Graph(int size) {
            firstVertices = size;
            secondVertices = 0;
            edges = new HashMap<>();
        }

        public boolean addEdge(int x, int y, boolean regularV) {
            if(!(0<=x && x<=firstVertices && firstVertices<y && y<=firstVertices+secondVertices) && regularV) {
                System.err.println("The graph is no longer bipartite. The execution is aborted.");
                System.exit(1);
            }

            if(!edges.containsKey(x))
                edges.put(Integer.valueOf(x), new LinkedList<Edge>());

            Edge temp = new Edge(x,y);
            if(!edges.get(x).add(temp))
                return false;

            size++;

            return true;
        }

        public boolean addEdge(Edge newEdge) {
            if(!edges.containsKey(newEdge.getStartVertex()))
                edges.put(Integer.valueOf(newEdge.getStartVertex()), new LinkedList<Edge>());

            if(!edges.get(newEdge.getStartVertex()).add(newEdge))
                return false;

            size++;

            return true;
        }

        public void changeNumOfXs(int newVal) {
            firstVertices = newVal;
        }

        public void changeNumOfYs(int newVal) {
            secondVertices = newVal;
        }

        public int getNumOfXs() {
            return firstVertices;
        }

        public int getNumOfYs() {
            return secondVertices;
        }

        public int numOfEdges() {
            return size;
        }

        public HashMap<Integer, LinkedList<Edge>> getEdges() {
            return edges;
        }

        public void printGraph(Kattio io) {
            printGraph(io, size-1, size);
        }

        public void printGraph(Kattio io, int source, int sink) {
            io.println(firstVertices+secondVertices);
            io.println(source + " " + sink);
            io.println(size);
            ArrayList<Edge> printed = new ArrayList<>();
            for(LinkedList<Edge> i : edges.values())
                for(Edge j : i)
                    if(!printed.contains(j)) {
                        printed.add(j);
                        io.println(j.getStartVertex() + " " + j.getEndVertex() + " " + j.getCapacity());
                    }
            io.flush();
        }

        public int numVertices() {
            return firstVertices+secondVertices;
        }

        public int numEdges() {
            return size;
        }
    }

public class Edge {
    private final int startVertex;
    private final int endVertex;
    private int flow;
    private int rCapacity;
    private final int capacity;

    public Edge(int start, int end) {
        startVertex = start;
        endVertex = end;
        flow = 0;
        rCapacity = 1;
        capacity = 1;
    }

    public Edge(int start, int end, int cap) {
        startVertex = start;
        endVertex = end;
        flow = 0;
        rCapacity = cap;
        capacity = cap;
    }

    public void changeFlow(int newFlowVal) {
        flow = newFlowVal;
    }

    public void changeResCap(int newResCapVal) {
        rCapacity = newResCapVal;
    }

    public int getStartVertex() {
        return startVertex;
    }

    public int getEndVertex() {
        return endVertex;
    }

    public int getFlow() {
        return flow;
    }

    public int getCapacity() {
        return capacity;
    }

    public int getResCapacity() {
        return rCapacity;
    }
}

我主要遵循维基百科对使用邻接节点的Edmond-Karp算法的描述,但也有一点来自其他来源但不是那么多。维基百科上的算法链接如下:

https://en.wikipedia.org/wiki/Edmonds - Karp_algorithm#伪代码

我的实现中是否存在某些地方,我在维基百科上解释了伪代码是错误的还是更具体地用我的Java代码?我几乎整天都在使用这个程序而没有弄清楚是什么原因导致某些图形的程序没有输出某些图形的最大匹配(或最大流量)的问题。

我将非常感谢您从我这里获得的所有帮助。

提前谢谢大家!

0 个答案:

没有答案