折叠的定义如下: 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))
思路:
f[i][j] 代表 i 到 j 之间的折叠成最小的长度。
首先我们要判断是不是有折叠的。
如果有,判断折叠多少次,因为是有数字在里面的。要计算数字的位数。
如果不能折叠,有枚举 k 的位置,然后用区间动规做出来。
#include<bits/stdc++.h>
using namespace std;
char s[200];
int tot;
int f[200][200];
bool check(int x, int y,int z){
if ((y - x + 1) % (z - x +1)) return 0; //是够整除。
for (int i = x; i <= y; i++)
if (s[i] != s[(i-x)%(z-x+1) + x]) return 0; //判断是不是重复的,
int tt = (y - x + 1) / (z - x + 1); //有多少个重复的。
tot = 0;
while(tt){ //判断有几位数。
tt /= 10;
tot++;
}
return 1;
}
int main(){
int n;
scanf("%s",s);
n = strlen(s);
for (int i = 0; i < n; i++) f[i][i] = 1;
for (int len = 2; len <= n; len++){
for (int i = 0; i <= n - len; i++){
int j = i + len - 1;
f[i][j] = len; //初始化。
for (int k = i; k < j; k++){
if (check(i,j,k)) f[i][j] = min(f[i][j],f[i][k] + 2 + tot); //如果重复。
f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]); //不重复,直接加起来。
}
}
}
printf("%d\n",f[0][n-1]);
return 0;
}