b_lg_字串摺疊(摺疊與不折疊取最優)
阿新 • • 發佈:2020-09-15
給一個字串,求它的最短折疊。例如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)\),