UVA 1351 - String Compression
区间dp,dp存该区间能压缩的最小长度。
对于每个区间可以被分成两个子区间,或者该区间可以压缩。预处理出每个区间可以最多的由几个子串重复组成:c[i][j]。
dp[i][j] = min{dp[i][k] + dp[k][j], digits(s) + dp[i][l] + 2};
l = (j-i+1)/c[i][j];
s = c[i][j];
而对于c数组的预处理可以O(n^3)完成。枚举重复子串的长度和起始位置,然后从起始位置找,每找到一个串c[i][j]+1;具体见代码。
问一个字符串经过压缩后最短可以到多短。压缩规则是如果有连续的重复子串(如:abcabcabcad)可以压缩成重复次数 + ( 重复子串) (前面例子的答案: 3(abc)ad )。压缩后的串长度要把数字和括号计算在内。
区间dp,dp存该区间能压缩的最小长度。
对于每个区间可以被分成两个子区间,或者该区间可以压缩。预处理出每个区间可以最多的由几个子串重复组成:c[i][j]。
dp[i][j] = min{dp[i][k] + dp[k][j], digits(s) + dp[i][l] + 2};
l = (j-i+1)/c[i][j];
s = c[i][j];
而对于c数组的预处理可以O(n^3)完成。枚举重复子串的长度和起始位置,然后从起始位置找,每找到一个串c[i][j]+1;具体见代码。
#include <bits/stdc++.h>
using namespace std;
const int INF = 999999999;
int len;
char s[205];
int _c[205][205];
int dp[205][205];
int _degits(int num) {
int cnt = 0;
while (num) {
cnt++;
num /= 10;
}
return cnt;
}
void _solve() {
for(int i=0; i<len; i++) {
for (int j=i; j<len; j++) {
_c[i][j] = 1;
}
}
for (int l=1; l<=len; l++) {
for (int i=0; i<len; i++) {
for (int j=i+l; j<len; j++) {
if (s[j] != s[i + (j-i-l)%l]) break;
if ((j-i-l) % l == l-1) {
_c[i][j] = max(_c[i][j], _c[i][j-l] + 1);
}
}
}
}
}
int main () {
int T;
for (scanf ("%d", &T); T>0; T--) {
scanf ("%s", s);
len = strlen(s);
_solve();
for (int i=0; i<len; i++) {
dp[i][i] = 1;
}
for (int j=1; j<len; j++) {
for (int i=j-1; i>=0; i--) {
dp[i][j] = INF;
for (int k=i; k<j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
}
int l = (j-i+1)/_c[i][j];
dp[i][j] = min(dp[i][j], dp[i][i+l-1] + 2 + _degits(_c[i][j]));
}
}
printf ("%d\n", dp[0][len-1]);
}
return 0;
}