1306:Balloon Collecting

バルーンが落ちてくる位置と時間が与えられる。
台車が運べるバルーンは3つまでである。
全てのバルーンを拾うことができるか。
また、そのときの最小の移動距離は?
もし全てのバルーンを拾うことができなければ
拾うことができない最初のバルーンの番号を求めよ。


動的計画法で解いた。
dp[バルーンの番号][台車が運んでいる個数]:=最小の移動距離

#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>

#define INF 1<<29

using namespace std;

int main(void){

  int n,dp[45][4],a,b;
  vector<int>p,t;

  while(cin >> n,n){
    p.clear();
    t.clear();
    
    fill(dp[0],dp[42],INF);
    
    for(int i=0;i<n;i++){
      cin >> a >> b;
      p.push_back(a);
      t.push_back(b);
    }

    dp[0][0]=p[0];
    if(p[0]>t[0]){
      cout << "NG " << 1 <<endl;
      continue;
    }
    int cnt=1;
    for(int i=1;i<n;i++){
      for(int j=1;j<4;j++){
	if(dp[i-1][j-1]==INF)continue;
	cnt=i;
	if(j<3 && abs(p[i]-p[i-1])*(j+1)<=t[i]-t[i-1])
	  dp[i][j]=min(dp[i][j],dp[i-1][j-1]+abs(p[i]-p[i-1]));
	if(p[i]+(p[i-1]*(j+1))<=t[i]-t[i-1])
	  dp[i][0]=min(dp[i][0],dp[i-1][j-1]+p[i]+p[i-1]);
      }
    }
    
    int ans=INF;
    for(int i=0;i<4;i++){
      ans=min(ans,dp[n-1][i]);
    }
    if(ans==INF)cout << "NG " << cnt+1 <<endl;
    else cout << "OK " << ans+p[p.size()-1] << endl;
  }

  return 0;
}