import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.PriorityQueue; import java.util.Scanner; /** * Solution to Treasure Map * * @author vanb */ public class treasure_vanb { private static Scanner sc; private static PrintStream ps; /** * This is a state of the search: The Mine we're going to, the amount of Gold we've got, and the Time of our arrival. * * @author vanb */ private class State implements Comparable { /** Index of the mine we're visiting */ public int mine; /** The amount of gold we have when we arrive */ public int gold; /** Our time of arrival */ public int time; /** * Create a State. * * @param mine Index of the mine we're visiting * @param gold The amount of gold we have when we arrive * @param time Our time of arrival */ public State( int mine, int gold, int time ) { this.mine = mine; this.gold = gold; this.time = time; } @Override /** * Compare this Sate with another, to order the search. * * @param other Another State to compare with * @return >0 if this state is "better", 0 if they're the same, <0 if this state is "worse" that the other. */ public int compareTo( State other ) { // We want to first sort by time, earlier is better. int diff = time - other.time; // Same time? More gold is better. if( diff==0 ) diff = other.gold - gold; // Everything else the same? it just doesn't matter, // but we need a comparison for uniqueness. if( diff==0 ) diff = mine - other.mine; return diff; } /** * Produce a pretty String for debugging. * * @return A pretty String for debugging */ public String toString() { return "[Mine=" + (mine+1) + ", Gold=" + gold + ", Time=" + time + "]"; } } /** * A Path to another Mone. * * @author vanb */ private class Path { /** The Mine this Path leads to */ public int destination; /** The time it takes */ public int cost; /** * Create a Path. * * @param destination The Mine this Path leads to * @param cost The time it takes */ public Path( int destination, int cost ) { this.destination = destination; this.cost = cost; } } /** * A Mine. * * @author vanb */ private class Mine { /** The amount of Gold mineable from here at time 0 */ public int gold; /** The amount by which the available gold decreases in 1 time unit */ public int decrease; /** * In the search, this is the last amount of gold we had * when we last visited this Mine BEFORE collecting its gold. */ public int lastgold; /** A list of the Paths leading away from this Mine */ public List paths; /** * Create a Mine. * * @param gold The amount of Gold mineable from here at time 0 * @param decrease The amount by which the available gold decreases in 1 time unit */ public Mine( int gold, int decrease ) { this.gold = gold; this.decrease = decrease; this.lastgold = -1; this.paths = new ArrayList(1000); } } /** * Do it! */ private void doit() { // Number of Mines int n = sc.nextInt(); // Number of Paths int m = sc.nextInt(); // Read the mines, and at the same time, // figure out the time at which all mines will yield 0 gold (maxtime). int maxtime = 0; Mine mines[] = new Mine[n]; for( int i=0; i 0 ) ++time; if( time>maxtime ) maxtime = time; } System.err.println( "maxtime " + maxtime ); // Read the Paths for( int i=0; i q = new PriorityQueue(); q.add( new State( 0, 0, 0 ) ); while( !q.isEmpty() ) { State s = q.poll(); System.err.println( s ); // If we're past maxtime, then all Mines yield 0 gold. // Might as well stop. if( s.time>maxtime ) break; // The States are ordered by time, so any States we've already seen in the search were earlier // or at the same time, never later. If we've already seen this much gold or more // when visiting this Mine, then there's no reason to visit this Mine now. Mine mine = mines[s.mine]; if( s.gold <= mine.lastgold ) continue; mine.lastgold = s.gold; // This is how much gold we have in total after visiting this Mine. int newgold = s.gold + Math.max( mine.gold - mine.decrease*s.time, 0 ); //System.err.println( newgold + " " + Math.max( mine.gold - mine.decrease*s.time, 0 ) ); if( newgold > maxgold ) maxgold = newgold; // Follow all of this Mine's Paths for( Path path : mine.paths ) { q.add( new State( path.destination, newgold, s.time + path.cost ) ); } } ps.println( maxgold ); } /** * Main! * * @param args Command-line args (unused) * @throws Exception */ public static void main( String[] args ) throws Exception { sc = new Scanner( System.in ); ps = System.out; new treasure_vanb().doit(); System.exit(0); } }