思路:要是对原串区间dp感觉无从下手,需要重要的一步就是转化,转化成连续的01数量串,比如10010=1211
这样的话每隔一个就是同一类的。
对于单个数字,需要的就是3-a[i],
对于一个区间,可以由三类转移
1. 把区间分成 两份 例如 11 00 ans=2
2.中间消去两头相遇消去 例如11 00 1 ans=1
3.三块相遇消去 例如 1 00 1 00 11 ans=2
第三种情况这三块要满足中间必须是1,两边加起来和<=3, 因为这样消去 第一个00的时候,才不会出现将1消去的情况,
然后消去第二个00,三块相遇消去
#include<bits/stdc++.h>
using namespace std;
int dp[210][210], a[210];
char s[210];
int main(){
int T, cas=0;
scanf("%d", &T);
while(T--){
scanf("%s", s);
int len=strlen(s);
int m=1; a[m]=1;
for(int i=1; i<len; i++){
if(s[i]==s[i-1]) a[m]++;
else a[++m]=1;
}
memset(dp, 0x3f, sizeof dp);
for(int i=1; i<=m; i++)dp[i][i]=3-a[i], dp[i][i-1]=0;
for(int t=1; t<m; t++){
for(int i=1; i+t<=m; i++){
int j=i+t;
for(int k=i; k<j; k++){
dp[i][j]=min(dp[i][j], dp[i][k]+dp[k+1][j]);
if(t>=4 && a[k]==1 && ((k-i+1)&1) && ((j-k+1)&1) && a[i]+a[j]<=3)
dp[i][j]=min(dp[i][j], dp[i+1][k-1]+dp[k+1][j-1]);
}
if((t+1)&1)
dp[i][j]=min(dp[i][j], dp[i+1][j-1]+(a[i]+a[j]==2));
}
}
printf("Case #%d: %d\n", ++cas, dp[1][m]);
}
return 0;
}