【洛谷P2470】[SCOI2007]压缩
压缩
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define MAXN 55 #define INF 0x3f3f3f3f #define mid ((l+r)>>1) int n,f[MAXN][MAXN][2]; //不妨处理每个子串时,我们都在它的前面放一个M,最后答案长度-1即可 //f[l][r][0]表示子串[l,r]中除了前面的M,串中还存在其他的M的最短长度 //f[l][r][1]则表示只有前面一个M的最短长度 /* 三个转移方程: 1.if(该串左右两半相同) f[l][r][1]=min(f[l][r][1],f[l][mid][1]+1); 压缩与不压缩 2. i l~r-1 f[l][r][1]=min(f[l][r][1],f[l][i][1]+r-i); 3. i l~r-1 f[l][r][0]=min(f[l][r][0],min(f[l][i][0],f[l][i][1])+min(f[i+1][r][0],f[i+1][r][1])); */ char s[MAXN]; int dp(int l,int r,bool op){ if(f[l][r][op]) return f[l][r][op]; if(l==r) return f[l][r][op]=2; int &d=f[l][r][op]=r-l+2; if(op){ bool flag=1; if((r-l+1)%2==1) flag=0; if(flag) for(int i=l;i<=mid;i++) if(s[i]!=s[mid+i-l+1]){ flag=0; break; } if(flag) d=min(d,dp(l,mid,1)+1); for(int i=l;i<r;i++) d=min(d,dp(l,i,1)+r-i); } else for(int i=l;i<r;i++) d=min(d,min(dp(l,i,0),dp(l,i,1))+min(dp(i+1,r,0),dp(i+1,r,1))); return d; } int main() { scanf("%s",s+1); n=strlen(s+1); dp(1,n,0); dp(1,n,1); printf("%d\n",min(f[1][n][0],f[1][n][1])-1); return 0; }