Description
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则AB A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
题解
区间dp,写得很少,我很弱。
当k+1~r可以由l~k重复得到时还要:f[l][r]=min(f[l][r],f[l][k]+2+count((r-l+1)/(k-l+1)));count是用来计算一个十进制数所占位数的。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
char ch[105];
int n,f[105][105];//表示从i到j的最短长度
int count(int x)
{
int ans=0;
while(x>0) {ans++; x/=10;}
return ans;
}
void dp()
{
int i,j,k,l,p;
for(l=1;l<=n+1;l++)
for(i=0;i+l-1<=n;i++)
{j=i+l-1;
f[i][j]=l;
for(k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
for(k=1;k<l;k++)
{if(l%k==0)
{bool b=1;
for(p=i+k;p+k-1<=j;p+=k)
{if(strncmp(ch+i,ch+p,k)) b=0;//话说这个函数我之前还不知道怎么用呢
if(!b) break;
}
if(b)
f[i][j]=min(f[i][j],f[i][i+k-1]+2+count(l/k));
}
}
}
}
int main()
{
scanf("%s",ch);
n=strlen(ch)-1;
dp();
printf("%d\n",f[0][n]);
return 0;
}