给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M
(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程:
已经解压的部分 | 解压结果 | 缓冲串 |
---|---|---|
b | b | b |
bM | b | . |
bMc | bc | c |
bMcd | bcd | cd |
bMcdR | bcdcd | cdcd |
bMcdRR | bcdcdcdcd | cdcdcdcd |
输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
输出仅一行,即压缩后字符串的最短长度。
代码
1 #include<bits/stdc++.h> 2 #define re register int 3 #define ll long long 4 #define maxn 55 5 using namespace std; 6 char as[maxn]; 7 int dp[maxn][maxn][3]; 8 int n; 9 int check(int l,int r){ 10 if((r-l+1)&1)return 0; 11 int mid=(l+r)>>1; 12 for(re i=l;i<=mid;i++) 13 if(as[i]!=as[i+mid-l+1])return 0; 14 return 1; 15 }//判断前一段和后一段是否相等 16 int main(){ 17 scanf("%s",as+1); 18 n=strlen(as+1);//长度 19 memset(dp,0x3f,sizeof(dp)); 20 for(re i=1;i<=n;i++) 21 for(re j=i;j<=n;j++) 22 dp[i][j][0]=dp[i][j][1]=(j-i+1);//初始为区间长度 23 for(re len=2;len<=n;len++) 24 for(re l=1;l+len-1<=n;l++){ 25 int r=l+len-1; 26 if(check(l,r))dp[l][r][0]=min(dp[l][(l+r)/2][0]+1,dp[l][r][0]);//相等的话 27 for(re k=l;k<r;k++){ 28 dp[l][r][0]=min(dp[l][r][0],dp[l][k][0]+r-k);//普通区间dp 29 } 30 for(re k=l;k<r;k++) 31 dp[l][r][1]=min(dp[l][r][1],min(dp[l][k][0],dp[l][k][1])+min(dp[k+1][r][0],dp[k+1][r][1])+1);//后面有M的时候 32 } 33 printf("%d\n",min(dp[1][n][1],dp[1][n][0]));//输出最后的结果 34 return 0; 35 }
虽然渺小,但不放弃。
原文:https://www.cnblogs.com/yzzy/p/13292234.html