1. 程式人生 > 實用技巧 >b_lg_字串摺疊(摺疊與不折疊取最優)

b_lg_字串摺疊(摺疊與不折疊取最優)

給一個字串,求它的最短折疊。例如AAAAAAAAAABABABCCD的最短折疊為:9(A)3(AB)CCD。
輸入格式
僅一行,即字串S,長度保證不超過100。
輸出格式
僅一行,即最短的摺疊長度。

輸入
NEERCYESYESYESNEERCYESYESYES
輸出
14
說明/提示
一個最短的摺疊為:2(NEERC3(YES))

方法一:dp

摺疊不一定比摺疊後的字串更短,所以這裡有兩種選擇:

  • 摺疊:需要列舉的子串是否有迴圈節,如果有,計算長度即可
  • 不折疊,則 f[i][j]=min(f[i][j], f[i][k]+f[k+1][j])
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int m[N], f[N][N];
string s;

bool chk(int l, int r, int sz) {
    for (int i=l; i<=r-sz; i++) if (s[i]!=s[i+sz])
        return false;
    return true;
}
void init() {
    for (int i=1; i<10; i++) m[i]=1;
    for (int i=10; i<100; i++) m[i]=2;
    m[100]=3;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>s; 
    int n=s.size(); s=" "+s;
    init();
    memset(f, 0x3f3f3f3f, sizeof f);
    for (int i=1; i<=n; i++) f[i][i]=1;
    
    for (int len=2; len<=n; len++)
    for (int i=1; i<=n-len+1; i++) {
        int j=i+len-1;
        for (int k=i; k<j; k++) {
            int sz=k-i+1;      //sz是迴圈節的大小
            if (len%sz==0 && chk(i,j,sz)) { 
                f[i][j]=min(f[i][j], f[i][k]+2+m[len/sz]);
            }
        }
        for (int k=i; k<j; k++) {
            f[i][j]=min(f[i][j], f[i][k]+f[k+1][j]);
        }
    }
    cout << f[1][n];
    return 0;
}

複雜度分析

  • Time\(O(n^3)\)
  • Space\(O(n^2)\)