3670:Eating Together
keyword
動的計画法 C
概要
1,2,3が並んだ長さN(<30000)の列が与えられる。このとき、数字を書き換えることによって減少列か増加列にしたい。数字の書き換え回数を最小化する問題。
分かりやすいDP。減少と増加は別々に考える。dp[i項目][i-1項目の数値]とすれば全状態数は3*Nしかない。また状態遷移は1->2, 2->3だけでなく1->3があることにも注意。
nt solve(){ int ret = 1<<29, i,j; for(i=0;i<N;i++) as[i]--; //check up for(i=0;i<=N;i++) for(j=0;j<3;j++) dp[i][j] = 1<<29; dp[0][0] = dp[0][1] = dp[0][2] = 0; for(i=0;i<N;i++){ for(j=0;j<3;j++){ dp[i+1][j] = min(dp[i+1][j], dp[i][j] + (as[i]==j?0:1)); if(j<2) dp[i+1][j+1] = min(dp[i+1][j+1], dp[i][j]+(as[i]==j+1?0:1)); if(j<1) dp[i+1][j+2] = min(dp[i+1][j+2], dp[i][j]+(as[i]==j+2?0:1)); } } ret = min(ret, dp[N][0]); ret = min(ret, dp[N][1]); ret = min(ret, dp[N][2]); //check down for(i=0;i<=N;i++) for(j=0;j<3;j++) dp[i][j] = 1<<29; dp[0][0] = dp[0][1] = dp[0][2] = 0; for(i=0;i<N;i++){ for(j=0;j<3;j++){ dp[i+1][j] = min(dp[i+1][j], dp[i][j] + (as[i]==j?0:1)); if(j>0) dp[i+1][j-1] = min(dp[i+1][j-1], dp[i][j]+(as[i]==j-1?0:1)); if(j>1) dp[i+1][j-2] = min(dp[i+1][j-2], dp[i][j]+(as[i]==j-2?0:1)); } } ret = min(ret, dp[N][0]); ret = min(ret, dp[N][1]); ret = min(ret, dp[N][2]); return ret; }