SCOI 2003 字符串折叠(区间 dp)

Description

求一个字符串的最短可嵌套压缩长度。如 AAAAAAAAAABABABCCD 最短为 9(A)3(AB)CCD

1 ≤ ∣ S ∣ ≤ 100 1 \leq |S| \leq 100 1S100

Solution

对于一个字符串,令 f i , j f_{i,j} fi,j [ i , j ] [i,j] [i,j] 的最短压缩长度,有三个压缩。

  1. 原串形式,将 f i , j f_{i,j} fi,j 赋初值为 j − i + 1 j-i+1 ji+1
  2. 拼接形式,枚举拼接点 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}
  3. 嵌套形式,枚举嵌套的周期长度,若能嵌套,则转移,与重复次数的位数 + 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;
} 
posted @ 2020-02-20 10:46  ylxmf2005  阅读(26)  评论(0)    收藏  举报