​传送门​

定义 f [ i ] [ j ] f[i][j] f[i][j]为消除 [ i , j ] [i,j] [i,j]的最小花费

如果 a [ i ] a[i] a[i]和 a [ j ] a[j] a[j]同色,那么可以消除中间再消两边

f [ i ] [ j ] = f [ i + 1 ] [ j − 1 ] + ( 消 除 a i , a j 的 代 价 ) f[i][j]=f[i+1][j-1]+(消除a_i,a_j的代价) f[i][j]=f[i+1][j−1]+(消除ai,aj的代价)

也可以采用分段消除枚举分割点 k k k

f [ i ] [ j ] = f [ i ] [ k ] + f [ k + 1 ] [ j ] f[i][j]=f[i][k]+f[k+1][j] f[i][j]=f[i][k]+f[k+1][j]

一般的区间dp就这么完事了,但是这个不同

两端的球可以和中间某个球合并

f [ i ] [ j ] = f [ i + 1 ] [ k − 1 ] + f [ k + 1 ] [ j − 1 ] f[i][j]=f[i+1][k-1]+f[k+1][j-1] f[i][j]=f[i+1][k−1]+f[k+1][j−1]

#include <bits/stdc++.h>
using namespace std;
const int maxn = 309;
char s[maxn];
int a[maxn],f[maxn][maxn],casenum;
int main()
{
int t; scanf("%d",&t);
while( t-- )
{
scanf("%s",s);
int n = strlen( s ),top=1;
a[top] = 1;
for(int i=1;i<n;i++)
{
if( s[i]==s[i-1] ) a[top]++;
else a[++top] = 1;
}
memset( f,20,sizeof(f) );
for(int i=1;i<=top;i++) f[i][i] = 3-a[i];

for(int l=2;l<=top;l++)
for(int i=1;i+l-1<=top;i++)
{
int j = i+l-1;
for(int k=i;k<j;k++)
f[i][j] = min( f[i][j],f[i][k]+f[k+1][j] );
if( (j-i+1)%2==0 ) continue;//不同色
if( a[i]+a[j]==2 )
f[i][j] = min( f[i][j],f[i+1][j-1]+1);
else
f[i][j] = min( f[i][j], f[i+1][j-1] );
if( a[i]+a[j]==4 ) continue;
for(int k=i+2;k<j;k+=2)
if( a[k]==1 )
f[i][j] = min( f[i][j],f[i+1][k-1]+f[k+1][j-1] );
}
printf("Case #%d: %d\n",++casenum,f[1][top] );
memset( a,0,sizeof(a) );
}
}