package MaxFlowApplet.graph; import java.util.Vector; class BFS { public BFS(Graph _graph) { graph = _graph; }; // initalizes the graph and executes the main BFS loop public void start() { int vertexNo; FlowVertex v; vertexNo = graph.numberOfVertices(); for(int i = 0; i < vertexNo; i++) { v = (FlowVertex) graph.getVertex(i); v.setPredecessor(null); v.setBFSColor(_WHITE); } ((FlowVertex) graph.getSource()).setBFSColor(_GRAY); mainLoopBFS(); }; protected boolean isEdge(FlowEdge e) { return (e.getResidualCapacity() > 0); }; // implements the main BFS loop protected void mainLoopBFS() { Queue vertexQueue = new Queue(); FlowVertex u; FlowVertex v; FlowEdge e; int fanOut; vertexQueue.enqueue(graph.getSource()); while(vertexQueue.empty() == false) { u = (FlowVertex) vertexQueue.atHead(); fanOut = u.fanOut(); for(int i = 0; i < fanOut; i++) { e = (FlowEdge) u.getEdgeOut(i); if (isEdge(e)) { v = (FlowVertex) e.getVertexTo(); if (v.getBFSColor() == _WHITE) { v.setBFSColor(_GRAY); v.setPredecessor(u); vertexQueue.enqueue(v); } } } vertexQueue.dequeue(); u.setBFSColor(_BLACK); } }; protected Graph graph; private static final int _WHITE = 0; private static final int _BLACK = 1; private static final int _GRAY = 2; }; //********************************************************************** class Queue extends java.util.Vector { Queue(int initSize) { super(initSize); }; Queue() { super(); }; Queue(int initSize, int capacityIncrement) { super(initSize, capacityIncrement); }; // inserts an item at the tail of the queue public void enqueue(Object newObject) { insertElementAt(newObject, 0); }; // removes an item from the head of the queue public void dequeue() { removeElementAt(size() - 1); } // true iff the queue is empty public boolean empty() { return isEmpty(); } // returns the item at the head of the queue public Object atHead() { return lastElement(); }; }; //********************************************************************** // precondition: every edge capacity is nonnegative public class MaxFlow { public MaxFlow(Graph _graph) { graph = _graph; residualEdges = new Vector(); init(); }; // reset flow to 0 public void init() { FlowEdge e; int n = graph.numberOfEdges(); int i; for(i = 0; i < n; i++) { e = (FlowEdge) graph.getEdge(i); e.setFlow(0); } n = residualEdges.size(); for(i = 0; i < n; i++) { e = (FlowEdge) residualEdges.elementAt(i); e.setFlow(0); } }; // run one step of the MaxFlow algorithm (one augmenting path) protected void runOneStep() { FlowVertex sink; FlowVertex v; FlowVertex u; FlowEdge e; FlowEdge h; FlowVertex source = (FlowVertex) graph.getSource(); // find the shortest path from source to sink BFS flowBFS = new BFS(graph); flowBFS.start(); sink = (FlowVertex) graph.getSink(); // if no path then the algorithm is done if (!isFinished()) // if there are augmenting paths { //find the minimum path capacity int minResCap = Integer.MAX_VALUE; v = sink; do { u = v.getPredecessor(); e = (FlowEdge) u.getEdgeTo(v); minResCap = Math.min(e.getResidualCapacity(), minResCap); v = u; } while (u != source); //update the flow on the path v = sink; while (v != source) { u = v.getPredecessor(); // the edge u->v exists cause u is the predecessor of v e = (FlowEdge) u.getEdgeTo(v); // v->u may not exist h = (FlowEdge) v.getEdgeTo(u); // in that case create a new edge if (h == null) { h = new FlowEdge(); h.setVertexTo(u); h.setVertexFrom(v); residualEdges.addElement(h); } // increase the flow by the minimal capacity on the augmenting path e.setFlow(e.getFlow() + minResCap); // the flow in the opposite direction is negative h.setFlow(-e.getFlow()); v = u; } } }; private void prepareWorkGraph() { FlowVertex u; FlowEdge e; int n = residualEdges.size(); for(int i = 0; i < n; i++) { e = (FlowEdge) residualEdges.elementAt(i); u = (FlowVertex) e.getVertexFrom(); u.addEdgeOut(e); u = (FlowVertex) e.getVertexTo(); u.addEdgeIn(e); } }; private void restoreObtainedGraph() { FlowVertex u; FlowEdge e; int n = residualEdges.size(); for(int i = 0; i < n; i++) { e = (FlowEdge) residualEdges.elementAt(i); u = (FlowVertex) e.getVertexFrom(); u.removeEdgeOut(e); u = (FlowVertex) e.getVertexTo(); u.removeEdgeIn(e); } } // runs the algorithm for n step or until it is finished public void runSteps(int n) { prepareWorkGraph(); for(int i = 0; i < n; i++) { runOneStep(); if (isFinished()) break; } restoreObtainedGraph(); }; // runs the algorithm until it is finished public void runUntilFinish() { prepareWorkGraph(); do { runOneStep(); } while (!isFinished()); restoreObtainedGraph(); }; // true iff no augmenting path has been found public boolean isFinished() { return ((FlowVertex) graph.getSink()).getPredecessor() == null; }; public int currentFlow() { int result = 0; FlowEdge e; FlowVertex sink = (FlowVertex) graph.getSink(); int fanIn = sink.fanIn(); for(int i = 0; i < fanIn; i++) { e = (FlowEdge) sink.getEdgeIn(i); result += e.getFlow(); } return result; }; private Graph graph; private Vector residualEdges; };