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的题目。。。结果发现自己这方面太弱,于是到bzoj上找题做。
f[i][j]表示s[i~j]的最短折叠长度,状态转移:f[i][j]=min{f[i][k]+f[k+1][j]} (i<=k<j)
特殊情况:s[i~k]为s[k+1~j]的子串,则可以折叠,f[i][j]=min(f[i][j],折叠次数的位数+2+f[i][k])(2为2个括号)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s[150];
int f[150][150],len;
bool check(int x,int y,int z)
{
int o=x;
for(int i=y+1;i<=z;i++)
{
if(s[o]!=s[i]) return false;
o++;
if(o>y) o=x;
}
return true;
}
int main()
{
memset(f,63,sizeof(f));
scanf("%s",s);
len=strlen(s);
for(int i=0;i<len;i++)
for(int j=0;j<4;j++)
f[i][i+j]=j+1;
for(int l=4;l<len;l++)
for(int i=0;i+l<len;i++)
{
int j=i+l;
for(int k=i;k<j;k++)
{
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
int t1=k-i+1,t2=j-k;
//printf("%d %d\n",t1,t2);
//printf("%d %d %d\n",i,k,j);
if(t2%t1==0 && check(i,k,j)==true)
{
int o=t2/t1+1,w=0;
while(o>0)
{
o/=10;
w++;
}
f[i][j]=min(f[i][j],w+2+f[i][k]);
}
}
}
/*for(int l=5;l<len;l++)
for(int i=0;i+l<len;i++)
{
int j=i+l;
for(int k=i;k<=j;k++) printf("%c",s[k]);printf(" ");
printf("%d %d %d\n",i,j,f[i][j]);
}*/
printf("%d",f[0][len-1]);
}