import java.io.*; import java.util.*; import java.awt.geom.*; /** * Solution to Flooding Fields. * * We'll use Ford/Fulkerson's Max Flow algorithm. For each cell in the field, * and for each time slice, there will be two nodes: an In node, and an Out node, * with a link from In to Out. If a cow can move from cell A to cell B going from * time slice i to time slice i+1, then there will be a link from A[i].Out to B[i+1].In. * All links will have capacity 1. * * @author vanb */ public class floodingfields_vanb { public Scanner sc; public PrintStream ps; /** * A node of a max flow graph. */ public class Node { // Grid location of this node public int row, col; // For debugging public String name; // Has the node been visited? public boolean visited = false; // List of edges from this node public LinkedList edges = new LinkedList(); // If this node has been visited, what edge did we get here from? public Edge from = null; /** * Create a node, give it a name for debugging. * * @param name Pretty name for the node */ public Node( String name, int row, int col ) { this.name = name; this.row = row; this.col = col; } /** * Clear this node for a new graph */ public void clear() { visited = false; edges.clear(); from = null; } } /** * An edge of a max flow graph. */ public class Edge { Node destination; int capacity; Edge dual; 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 */ public void link( Node n1, Node n2, int cost ) { //System.err.println( "linking " + n1.name + " to " + n2.name ); 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 ); } /** Queue for the Ford/Fulkerson algorithm */ public LinkedList queue = new LinkedList(); /** * Perform the Ford/Fulkerson algorithm on a graph. * * @param src Source node * @param snk Sink node * @param nodes The graph, represented as a list of nodes * @return The max flow from the source to the sink */ public int fordfulkerson( Node src, Node snk, List nodes ) { int total = 0; // Keep going until you can't get from the source to the sink for(;;) { // Reset the graph for( Node node : nodes ) { node.visited = false; node.from = null; } // Reset the queue // Start at the source queue.clear(); queue.add( src ); src.visited = true; // 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.visited ) { // Node has been visited dest.visited = true; // Remember the edge that got us here dest.from = edge; // Add to the queue queue.add( dest ); } } } // If we were unable to get to the sink, then we're done if( !found ) break; // Otherwise, look along the path to find the minimum capacity int min = Integer.MAX_VALUE; for( Node node = snk; node.from != null; ) { Edge edge = node.from; if( edge.capacity < min ) min = edge.capacity; node = edge.dual.destination; } // Add that minimum capacity to the total total += min; // Go back along the path, and for each edge, move the min // capacity from the edge to its dual. for( Node node = snk; node.from != null; ) { Edge edge = node.from; edge.capacity -= min; edge.dual.capacity += min; node = edge.dual.destination; } } // Return the total return total; } /** * Driver. * @throws Exception */ public void doit() throws Exception { sc = new Scanner (System.in); ps = System.out; // Field elevations (pre-allocated) int field[][] = new int[1000][1000]; // Keep track of edges into a field grid node. Node ins[][] = new Node[1000][1000]; // The changes in row & col for the 5 kinds of cow movement int drow[] = { 0, 1, -1, 0, 0 }; int dcol[] = { 0, 0, 0, 1, -1 }; // A list of All Ford/Fulkerson nodes LinkedList nodes = new LinkedList(); // A list of Out nodes from the previous time slice LinkedList oldouts = new LinkedList(); // A list of Out nodes being created for the current time slice LinkedList newouts = new LinkedList(); // Used for swapping newouts & oldouts LinkedList temp; for(;;) { int n = sc.nextInt(); int k = sc.nextInt(); int h = sc.nextInt(); if( n==0 ) break; for( int i=0; i=0 && newrow=0 && newcol height ) { // If we haven't created nodes for this cell yet if( ins[newrow][newcol]==null ) { // Create the In node Node newin = new Node("In[" + newrow + "," + newcol + "]@" + i, newrow, newcol ); ins[newrow][newcol] = newin; nodes.add( newin ); // Create the Out node Node newout = new Node("Out[" + newrow + "," + newcol + "]@" + i, newrow, newcol ); newout.row = newrow; newout.col = newcol; nodes.add( newout ); newouts.add( newout ); // link In & Out link( newin, newout, 1 ); // Link the previous Out node to the new In node link( outnode, newin, 1 ); } else { // If the In node is already there, just link the previous Out node to it. link( outnode, ins[newrow][newcol], 1 ); } } } } } // Link all the remaining Outs to the Sink. for( Node node : newouts ) { link( node, sink, 1 ); } // Ford/Fulkerson!! ps.println( fordfulkerson( source, sink, nodes ) ); } } /** * @param args */ public static void main( String[] args ) throws Exception { long start = System.currentTimeMillis(); new floodingfields_vanb().doit(); System.err.println( System.currentTimeMillis()-start ); // Random random = new Random(); // PrintStream infile = new PrintStream( new FileOutputStream( "floodingfields.tmp" ) ); // // int n = 100; // int k = 100; // int h = 24; // int field[][] = new int[50][50]; // // for( int i=0; i<50; i++ ) // { // Arrays.fill( field[i], -1 ); // } // // // for( int i=0; i<24; i++ ) // { // field[23][23-i] = 0; // field[23][25+i] = 0; // field[24][23-i] = i; // field[24][25+i] = i; // field[25][23-i] = 0; // field[25][25+i] = 0; // } // field[23][49] = 0; // field[24][49] = 0; // field[25][49] = 0; // // for( int i=0; i<25; i++ ) // { // field[i][24] = 25-i; // if( i<24 ) // { // field[i][23] = 0; // field[i][25] = 0; // } // } // boolean seen[][] = new boolean[n][n]; // // infile.println( n + " " + k + " " + h ); // for( int i=0; i=0 ) //// { //// value = field[i][j]; //// seen[i][j] = true; //// } // infile.print( (j==0?"":" ") + value ); // } // infile.println(); // } // //// infile.println( "24 23" ); //// infile.println( "24 25" ); // for( int i=0; i