AOJ 1306 ICPC Asia resional 2010 Problem B: Balloon Collecting

問題

空から風船が落ちてくるので、それを台車で回収したい。
それぞれの風船は、時間t[i]にx座標x[i]の地点に落ちる。
このとき台車はちょうどx[i]の位置にいる必要がある。


台車は回収した風船を、x座標が0の地点の小屋に入れることができる。
台車には風船が3つまで乗り、風船がk個乗っているときに単位距離を移動するのにかかる時間はk+1である。


台車は時刻0のとき小屋にいる。
台車は風船を全て回収できるか、できるならそのときの移動距離の最小値を、
そうでないなら最初に回収できなくなる風船の番号を答えよ。

制約条件

n≦40
x[i]≦100
t[i]≦50000

方針

風船をi個回収したときの、位置x[j]にいて現在台車に乗っている風船がk個のときの移動の最小距離をdp[i][j][k]とする。

これを風船ごとに、一度小屋に寄ってからその風船を取るか、
直接風船を取るかを選ぶように更新していくdpをすればいい。

ソースコード

int n,X[100],t[100];
int dp[100][4];

int main()
{
	while(cin>>n,n){
		rep(i,n)cin>>X[i+1]>>t[i+1];
		
		rep(i,n+1)rep(k,4)dp[i][k]=1e9;
		dp[0][0]=0;
		
		rep(i,n)rep(k,4){
			if(k<3&&abs(X[i+1]-X[i])*(k+1)<=t[i+1]-t[i])
			dp[i+1][k+1]=min(dp[i+1][k+1],dp[i][k]+abs(X[i+1]-X[i]));
			if(X[i]*(k+1)+X[i+1]<=t[i+1]-t[i])
			dp[i+1][1]=min(dp[i+1][1],dp[i][k]+X[i]+X[i+1]);
		}
		int ans=1e9,mx;
		rep(k,4)ans=min(ans,dp[n][k]+X[n]);
		if(ans>=1e9){
			rep(i,n)rep(k,4)if(dp[i][k]<1e9)mx=i;
			cout<<"NG "<<mx+1<<endl;
			continue;
		}
		cout<<"OK "<<ans<<endl;
	}
	return 0;
}