SCOI 2003 字符串折叠(区间 dp)
Description
求一个字符串的最短可嵌套压缩长度。如 AAAAAAAAAABABABCCD 最短为 9(A)3(AB)CCD。
1 ≤ ∣ S ∣ ≤ 100 1 \leq |S| \leq 100 1≤∣S∣≤100
Solution
对于一个字符串,令 f i , j f_{i,j} fi,j 为 [ i , j ] [i,j] [i,j] 的最短压缩长度,有三个压缩。
- 原串形式,将 f i , j f_{i,j} fi,j 赋初值为 j − i + 1 j-i+1 j−i+1。
- 拼接形式,枚举拼接点 k k k, f i , j = min { f i , j , f i , k + f k + 1 , j } f_{i,j} = \min \{f_{i,j}, f_{i,k} + f_{k + 1, j} \} fi,j=min{fi,j,fi,k+fk+1,j}。
- 嵌套形式,枚举嵌套的周期长度,若能嵌套,则转移,与重复次数的位数 + 2 + 2 +2 即两个括号 + + + 周期长度取 min。
Code
#include <bits/stdc++.h>
using namespace std;
int n; string s;
int f[501][501];
int main(){
cin >> s; n = s.size();
for (int i = 0; i < n; i++) f[i][i] = 1;
for (int j = 0; j < n; j++)
for (int i = j - 1; i >= 0; i--){
f[i][j] = j - i + 1;
for (int k = i; k < j; k++)
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]);
for (int k = i; k < j; k++)
if (s[k] == s[j] && (j - i + 1) % (k - i + 1) == 0){
string tmp = s.substr(i, (k - i + 1));
int p = k;
while (p < j && s[p + 1] == tmp[(p - i + 1) % (k - i + 1)]) p++;
if (p == j) f[i][j] = min(f[i][j], int(ceil(log10((j - i + 1) / (k - i + 1) + 1))) + 2 + f[i][k]);
}
}
printf("%d\n", f[0][n - 1]);
return 0;
}

浙公网安备 33010602011771号