P4302 [SCOI2003]字符串折叠(区间dp好题)

题目描述

折叠的定义如下:

  1. 一个字符串可以看成它自身的折叠。记作S = S
  2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
  3. 如果A = A’, B = B’,则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。

输入格式

仅一行,即字符串S,长度保证不超过100。

输出格式

仅一行,即最短的折叠长度。

输入输出样例

输入 #1
NEERCYESYESYESNEERCYESYESYES
输出 #1
14

说明/提示

一个最短的折叠为:2(NEERC3(YES))

思路:折叠出来的括号和数字是算在内的,所以折叠后的长度要加上2和数字的长度1/2,我们预先暴力处理出所有的区间的最大折叠情况,然后区间dp

如果该区间可以折叠,则设置为求一下它折叠后的长度,然后再加上第三重循环,也就是用i-k区间的折叠长度加上k+1-j区间的折叠长度来松弛i-j这个区间

的折叠长度.

AC代码:

#include<bits/stdc++.h>
using namespace std;
int iswap[105][105];
int dp[105][105];
string a;
int main() {
    //freopen("test.txt", "r", stdin);
    cin >> a;
    int n = a.size();
    a.insert(a.begin(), 0);
    memset(dp, 0x3f, sizeof(dp));//初始化设置为一个很大的数
    for (int len = 2; len <= n; len++) {
        for (int i = 1, j = i + len - 1; j <= n; i++,j++){
            for (int k = 1; k <len; k++) {//k代表分成的小段的长度,从1开始
                if (len % k!=0)continue;
                int s = len / k;//小段的个数
                int l = i;
                string p = a.substr(l, k);
                s--; l += k;
                bool f = 1;
                while (s--) {//暴力匹配
                    string q = a.substr(l, k);
                    l += k;
                    if (q != p) { f = 0; break; }
                }
                if (f) {//匹配成功
                    iswap[i][j] =k; break;
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        dp[i][i] = 1;
    }//初始化长度为1的区间
    for (int len = 2; len <= n; len++) {
        for (int i = 1, j = i + len - 1; j <= n; i++,j++) {//套模板
            if (iswap[i][j]) {//如果该区间本身就可以折叠
                dp[i][j] = dp[i][i + iswap[i][j] - 1] + 2 + ((len / iswap[i][j]) >= 10 ? 2 : 1);
                //就设置为折叠后区间的最段长度+括号的2加上数字,这里数字可能为两位数所以注意判断
            }
            for (int k = i; k < j; k++) {//然后再看是否有跟好的区间合并方案
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
            }
        }
    }
    cout << dp[1][n] << endl;
    return 0;
}

 

posted @ 2021-03-22 10:04  cono奇犽哒  阅读(43)  评论(0)    收藏  举报