CII.HDU6212 Zuma
一眼区间DP。
首先,我们将串压缩(即将相同颜色的相邻珠子合并)。记\(col_i\)为位置\(i\)的颜色,\(sz_i\)为位置\(i\)的珠子数。
我们设\(f[i,j]\)表示消去区间\([i,j]\)中所有东西的最小步数。
则有:
\[f[i,j]=\min\begin{cases}3-sz_i&|i=j\\f[i,k]+f[k+1,j]&|i\leq k<j\\f[i+1,j-1]+\max(0,3-sz_i-sz_j)&|col_i=col_j\\f[i+1,k-1]+f[k+1,j-1]&|col_i=col_j=col_k,(sz_i\neq 2\lor sz_j\neq 2)\land sz_k=1\end{cases}
\]
其中,第一条转移是直接补满\(3\)个球;第二条转移是找个地方切一刀;第三条转移是将\(i\)和\(j\)最终合并在一起进行消除;第四条转移是将\(i\),\(j\),以及区间中某一个\(k\)合并消除,但需要保证有一种消除顺序可以使得\(k\)可以先在不与某一边一起消掉的前提下消到那一边,然后再合并两边。
时间复杂度\(O(Tn^3)\),需要保证常数。
代码:
#include<bits/stdc++.h>
using namespace std;
int T,n,m,sz[210],f[210][210];
bool col[210];
char s[210];
int main(){
scanf("%d",&T);
for(int t=1;t<=T;t++){
scanf("%s",s+1),m=strlen(s+1),n=0;
col[1]=s[1]-'0',sz[1]=1,n++;
for(int i=2;i<=m;i++){
if(s[i]-'0'==col[n])sz[n]++;
else n++,col[n]=s[i]-'0',sz[n]=1;
}
for(int i=1;i<=n;i++)f[i][i]=3-sz[i];
for(int l=2;l<=n;l++)for(int i=1,j=i+l-1;j<=n;i++,j++){
f[i][j]=0x3f3f3f3f;
for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
if(col[i]!=col[j])continue;
f[i][j]=min(f[i][j],f[i+1][j-1]+max(0,3-sz[i]-sz[j]));
if(sz[i]==2&&sz[j]==2)continue;
for(int k=i+1;k<j;k++)if(col[k]==col[i]&&sz[k]==1)f[i][j]=min(f[i][j],f[i+1][k-1]+f[k+1][j-1]);
}
printf("Case #%d: %d\n",t,f[1][n]);
}
return 0;
}