TopCoder SRM 381 Div1 Medium TheHomework
問題
数列firstに、以下の操作を繰り返してsecondにしたい。
(数の順番は一致してなくともよい)
- add 任意の数を加える。加える数の個数は元の数列の項数を超えてはならない
- delete 数を消す。消す数の個数は元の数列の項数の半分を超えてはならない
- change 数を変更する。変更する数の個数は元の数列の項数の半分を超えてはならない。
必要な操作の回数の最小値を求めよ。
方針
(一致している項の数、一致してない項の数)を状態とするメモ化再帰。
項の数が200を超えたら明らかに打ち切っていいので打ち切る。
循環したらINFになっているので単純に再帰して上手く行く。
Editorialの解法ではこれを幅優先探索で行っていた。
ソースコード
int m,dp[200][200];//一致、不一致 int rec(int a,int b){ if(a>=200||b>=200||a<0||b<0)return inf; if(dp[a][b]>=0)return dp[a][b]; if(a==m&&b==0)return 0; int &res=dp[a][b]; res=inf; int n=a+b; rep(i,min(n/2,b))res=min(res,1+rec(a+i+1,b-i-1)); rep(i,n)res=min(res,1+rec(a+i+1,b)); rep(i,min(n/2,b))res=min(res,1+rec(a,b-i-1)); return res; } class TheHomework { public: int transform(vector <int> first, vector <int> second) { rep(i,200)rep(j,200)dp[i][j]=-1; int n=first.size(); m=second.size(); int a=0,b=0; rep(i,n){ rep(j,second.size())if(first[i]==second[j]){ a++; second.erase(second.begin()+j); goto NEXT; } b++; NEXT:; } return rec(a,b); } };