TopCoder SRM 351 Div1 Medium BoxesArrangement
問題
A,B,C三種類からなる文字列が与えられる。
この文字列を、二つの文字を選び、その位置を入れ替えるような操作を繰り返して、「連続する3つの文字が同じ文字になっている」部分がないようにしたい。
このとき、"入れ替えの操作で触らなかった"文字の数を最大にしたい。
触らない文字の数の最大値はいくつか、求めよ。
制約条件
文字数≦50
方針
Aをa個,Bをb個,Cをc個、条件を満たすように並べながら、ペナルティを最小にすると考えても同じ。
動的計画法による。
dp[a][b][c][prev][continue]を、
Aをa文字使い、Bをb文字使い、Cをc文字使い、
一個前の文字がprevで、今その文字がcontinue文字だけ続いているような状態における、
不一致の文字の数の最小値とする。
これを更新していくようなDPをすればよい。
ソースコード
//A, B, C, prev, continue int dp[51][51][51][3][3]; class BoxesArrangement { public: int maxUntouched(string boxes) { int n=boxes.size(); rep(i,n+1)rep(j,n+1)rep(k,n+1)rep(l,3)rep(m,3)dp[i][j][k][l][m]=inf; dp[0][0][0][0][0]=0; rep(p,n)rep(i,p+1)rep(j,p+1-i)rep(k,p+1-i-j)if(i+j+k==p)rep(l,3)rep(m,3){ if(dp[i][j][k][l][m]!=inf)rep(cl,3){ int ni=i+(cl==0), nj=j+(cl==1), nk=k+(cl==2); int nc=l==cl?m+1:1, ncost=dp[i][j][k][l][m]+(boxes[p]-'A'!=cl); if(nc>2)continue; dp[ni][nj][nk][cl][nc]=min(dp[ni][nj][nk][cl][nc],ncost); } } int a=0, b=0, c=0, ans=inf; rep(i,n){ if(boxes[i]=='A')a++; if(boxes[i]=='B')b++; if(boxes[i]=='C')c++; } rep(i,3)rep(j,3)ans=min(ans,dp[a][b][c][i][j]); return ans==inf?-1:n-ans; } };