POJ 3404 Bridge over a rough river
問題
N人が橋を渡りたい。
橋は同時に2人までしか渡ることができず、また一つしかない懐中電灯を持って渡る必要がある。
それぞれの人に対して橋を渡るのにかかる時間が決まっている。
二人が同時に渡るときは遅い人に合わせる。
全員が橋を渡り終えるのにかかる時間を求めよ。
制約条件
N≦50
方針
dp[i][j]を、懐中電灯は橋のこちら側にあるとして、
- iが0: 2番目に早い人が橋のこちら側にいる 1: 2番目に早い人が橋の向こう側に居る
- j番目より遅い人が全て渡り終わっている
のにかかる最短の時間とする。
これを更新するようなDPで解ける。
DPの状態遷移は、二番目に早い人がこちらにいるときは、
「二番目に早い人が、一番早い人と向こう側へ行く」選択肢しかなく
二番目に早い人が向こう側にいるときは、
「一番早い人と一番遅い人が向こう側へいき、二番目に早い人が懐中電灯を持ち帰る」または
「一番遅い人と一番早い人が一緒に向こう側へ行き、一番早い人が懐中電灯を持ち帰る」
が考えられる。
ソースコード
int N,t[50]; int dp[2][50]; int rec(int sec,int last){ if(dp[sec][last]>=0)return dp[sec][last]; int &ret=dp[sec][last]; if(last<=1)return last==0||sec?t[0]:t[1]; if(last==2&&sec)return t[2]; ret=(int)1e9; if(sec==0){ ret=min(ret,rec(1,last)+t[0]+t[1]); } else{ if(last>2)ret=min(ret,rec(0,last-2)+t[last]+t[1]); ret=min(ret,rec(1,last-1)+t[last]+t[0]); } return ret; } int main(){ scanf("%d",&N); rep(i,N)scanf("%d",t+i); sort(t,t+N); if(N<=2){ printf("%d\n",N==1?t[0]:t[1]); return 0; } memset(dp,-1,sizeof(dp)); printf("%d\n",rec(0,N-1)); return 0; }