AOJ-1306: Balloon Collecting
問題概要
風船がN(<40)個落ちてくる。それぞれ落ちる位置x(<100)と時刻t(<50000)が与えられる。乗り物で風船を拾う。乗り物は最大で3つまで風船を積むことができて、x=0の位置で風船をリリースすることができる。乗り物は1単位距離移動するのに、(今搭載している風船の個数+1)単位時間かかる。全ての風船を拾ってリリースするまでに必要な総移動距離の最小値を求める問題。無理なときは幾つ目の風船が拾えないか答える。
解法
見た瞬間にDP。多分一番楽なのは状態をdp[i番目の風船][搭載している風船の個数]とする。計算量O(N)。dp[座標][時間][風船の個数]とやっても解けるかもしれない。意味ないけど。実装時間17分。
import java.util.Arrays; import java.util.Scanner; public class Main{ int N; int[] ps; int[] ts; void run(){ Scanner in = new Scanner(System.in); for(;;){ N = in.nextInt(); if(N==0) return ; ps = new int[N]; ts = new int[N]; for(int i=0; i<N; i++){ ps[i] = in.nextInt(); ts[i] = in.nextInt(); } int ans = solve(); if(ans > 0) System.out.println("OK " + ans); else System.out.println("NG " + (-ans)); } } int solve(){ int[][] dp = new int[N][3]; for(int i=0; i<N; i++){ Arrays.fill(dp[i], Integer.MAX_VALUE); } if(ts[0] < ps[0]) return -1; dp[0][0] = ps[0]; for(int i=0; i<N-1; i++){ for(int j=0; j<3; j++)if(dp[i][j] < Integer.MAX_VALUE){ if(ts[i] + (j+2)*ps[i] + ps[i+1] <= ts[i+1]){ dp[i+1][0] = Math.min(dp[i+1][0], dp[i][j] + ps[i] + ps[i+1]); } if(j<2 && ts[i] + (j+2)*Math.abs(ps[i]-ps[i+1]) <= ts[i+1]){ dp[i+1][j+1] = Math.min(dp[i+1][j+1], dp[i][j] + Math.abs(ps[i] - ps[i+1])); } } boolean ok = false; for(int j=0; j<3; j++){ if(dp[i+1][j] < Integer.MAX_VALUE){ ok = true; } } if(!ok){ return -(i+2); } } int ans = Integer.MAX_VALUE; for(int j=0; j<3; j++){ ans = Math.min(ans, dp[N-1][j]); } return ans + ps[N-1]; } public static void main(String args[]){ new Main().run(); } }