题意:给出一个字符串S,要求把字符串长度压缩的尽量短,如果有N个连续的字符串s相同,那么就可以把这多个字符串压缩成N(s),这样压缩后的长度为 N的位数+2(两个括号)+s的长度, 同样压缩后的N(s)还可以继续被压缩,求最短的字符串长度.
思路:首先找出各个区间的最短周期串长度(即这个区间一个串循环多次组成),定义一个cycle[i][j]表示[i,j]区间的最短周期串长度.
然后进行动态规划,设dp[i][j]为区间[i,j]的最短压缩长度,则可以有:
dp[i][j] = min{dp[i][k] + dp[k + 1][j], t}.这里的t只有当区间[i,j]存在一个周期串时才存在t,t = dp[i][i + cycle[i][j] - 1] + 2 + digits[(j - i + 1) / cycle[i][j]].
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int INF = 0x20202020;
const int MAX = 205;
int dp[MAX][MAX];
int cycle[MAX][MAX];
int digits[MAX];
char seq[MAX];
int LEN(int i, int j){
return min((j - i + 1), dp[i][i + cycle[i][j] - 1] + digits[(j - i + 1) / cycle[i][j]] + 2);
}
int main(int argc, char const *argv[]){
for(int i = 0; i < MAX; ++i){
int x = i;
while(x){
++digits[i];
x /= 10;
}
}
int T;
scanf("%d", &T);
while(T--){
scanf("%s", seq + 1);
int len = strlen(seq + 1);
memset(cycle, -1, sizeof(cycle));
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= len; ++i){
cycle[i][i] = 1;
dp[i][i] = 1;
for(int j = i + 1; j <= len; ++j){
int c = 1, l = j - i + 1;
for(; c <= l >> 1; ++c){
if(l % c)continue;
int ok = true;
for(int k = i + c; k <= j; ++k){
if(seq[k] != seq[(k - i) % c + i]){
ok = false;
break;
}
}
if(ok){
cycle[i][j] = c;
break;
}
}
dp[i][j] = j - i + 1;
}
}
for(int p = 1; p < len; ++p){
for(int i = 1; i + p <= len; ++i){
int j = i + p;
if(cycle[i][j] != -1){
dp[i][j] = LEN(i, j);
}
for(int k = i; k < j; ++k){
if(dp[i][k] + dp[k + 1][j] < dp[i][j]){
dp[i][j] = dp[i][k] + dp[k + 1][j];
}
}
}
}
printf("%d\n", dp[1][len]);
}
return 0;
}