import java.io.PrintStream; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * Solution to Room Evacuation using Dinic. * * @author vanb */ public class room_vanb_dinic { /** Input. */ private static Scanner sc; /** Output. */ private static PrintStream ps; /** * A node of a max flow graph. * * @author vanb */ private class Node { /** List of edges out from this node. */ public ArrayList edges = new ArrayList(); /** If this node has been visited, what edge did we get here from?. */ public Edge gothere = null; /** Minimum distance from the source to this node */ public int level = 0; } /** * An edge of a max flow graph. * * @author vanb */ private class Edge { /** The destination. */ Node destination; /** The capacity. */ int capacity; /** The dual. */ Edge dual; /** * Instantiates a new edge. * * @param d the Destination Node * @param c the Capacity */ public Edge( Node d, int c ) { capacity = c; destination = d; dual = null; } } /** * Create a link between two nodes of a max flow graph. * * @param n1 From node * @param n2 To node * @param cost Cost to go from n1 to n2 */ private void link( Node n1, Node n2, int cost ) { Edge e12 = new Edge( n2, cost ); Edge e21 = new Edge( n1, 0 ); e12.dual = e21; e21.dual = e12; n1.edges.add( e12 ); n2.edges.add( e21 ); } /** The room. */ private char room[][]; /** The size of the room. */ private int n, m; /** * Can a person go to room[i][j]? * * @param i the i * @param j the j * @return true, if room[i][j] exists and can be occupied. */ private boolean cango( int i, int j ) { return i>=0 && i=0 && j nodes ) { // This will be the final answer int total = 0; // A queue for BFS ArrayDeque queue = new ArrayDeque(nodes.size()); for(;;) { // Reset the graph for( Node node : nodes ) node.gothere = null; // Do a BFS to find levels queue.clear(); queue.add( src ); src.level = 0; src.gothere = new Edge( src, 0 ); while( queue.size()>0 ) { Node node = queue.poll(); int next = node.level+1; // Look for edges to traverse for( Edge edge : node.edges ) { Node dest = edge.destination; if( edge.capacity>0 && dest.gothere==null ) { // Add to the queue dest.gothere = edge; dest.level = next; queue.add( dest ); } } } boolean flow = false; for(;;) { // Reset the graph for( Node node : nodes ) node.gothere = null; // Reset the queue // Start at the source queue.clear(); queue.add( src ); // Have we found the sink? boolean found = false; // Use a breadth-first search to find a path from the source to the sink while( queue.size()>0 ) { Node node = queue.poll(); // Have we found the sink? If so, break out of the BFS. if( node==snk ) { found = true; break; } // Look for edges to traverse for( Edge edge : node.edges ) { Node dest = edge.destination; // If this destination hasn't been visited, // and the edge has capacity, // put it on the queue. if( edge.capacity>0 && dest.gothere==null && dest.level==node.level+1 ) { // Add to the queue dest.gothere = edge; queue.add( dest ); } } } // If we were unable to get to the sink, then we're done if( !found ) break; // We found a flow flow = true; // Add that flow to the total (it's always 1) ++total; // Go back along the path, and for each edge, move // the flow from the edge to its dual. for( Node node = snk; node.gothere != null; ) { Edge edge = node.gothere; --edge.capacity; ++edge.dual.capacity; node = edge.dual.destination; } } // If we didn't find a flow, we're done if( !flow ) break; } // Return the total return total; } /** * Do it!. */ private void doit() { n = sc.nextInt(); m = sc.nextInt(); int t = sc.nextInt()+1; room = new char[n][]; for( int i=0; i nodes = new ArrayList(n*m*t+2); Node source = new Node(); Node sink = new Node(); nodes.add( source ); nodes.add( sink ); Node graph[][][] = new Node[n][m][t]; for( int i=0; i