字符串折叠(区间dp)
题目链接:https://ac.nowcoder.com/acm/problem/20238
题目描述
折叠的定义如下:
一个字符串可以看成它自身的折叠。记作S = S X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
如果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
输出
复制
14
思路:
#include<bits/stdc++.h> #include<cstdio> #define ll long long using namespace std; const int MMAX=2e2+5; char s[MMAX]; int dp[MMAX][MMAX]; bool check(int l1,int r1,int l2,int r2) ///[l1,r1]是主串 { ///遍历判断是否是主串的子串 int rri=r2-l2+1; for(int i=l1;i<=r1;i++) { int lle=(i-l1)%rri; if(s[i]!=s[l2+lle]) return false; } return true; } int dfs(int l,int r) { int len=r-l+1; for(int le=1;le<=len;le++) { if(len%le==0) { if(check(l,r,l,l+le-1)) return le; ///寻找最小子串 } } } int main() { scanf("%s",s+1); int len=strlen(s+1); memset(dp,0,sizeof(dp)); for(int i=1;i<=len;i++) dp[i][i]=1; for(int le=2;le<=len;le++) ///枚举长度 { for(int l=1;l<=len-le+1;l++) ///枚举起点 { int r=l+le-1; ///确定终点 dp[l][r]=r-l+1; ///确定初始值 for(int k=l;k<r;k++) ///枚举断点 { int len1=k-l+1,len2=r-k; if(len1%len2==0) ///len1>len2 { if(check(l,k,k+1,r)) ///判断len2是否是len1的子串 { int su1=dfs(k+1,r); int su2=(len1+len2)/su1; int su3=(len1+len2)/min(len1,len2); ///最小子串合并 if(su2>=100) dp[l][r]=min(dp[l][r],su1+5); else if(su2>=10) dp[l][r]=min(dp[l][r],su1+4); else dp[l][r]=min(dp[l][r],su1+3); ///整个字符串整体合并 if(su3>=100) dp[l][r]=min(dp[l][r],dp[k+1][r]+5); else if(su3>=10) dp[l][r]=min(dp[l][r],dp[k+1][r]+4); else dp[l][r]=min(dp[l][r],dp[k+1][r]+3); } else dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]); } else if(len2%len1==0) ///len2>len1 { if(check(k+1,r,l,k)) ///判断len1是否是len2的子串 { int su1=dfs(l,k); int su2=(len1+len2)/su1; int su3=(len1+len2)/len1; ///最小子串合并 if(su2>=100) dp[l][r]=min(dp[l][r],su1+5); else if(su2>=10) dp[l][r]=min(dp[l][r],su1+4); else dp[l][r]=min(dp[l][r],su1+3); ///整个字符串整体合并 if(su3>=100) dp[l][r]=min(dp[l][r],dp[l][k]+5); else if(su3>=10) dp[l][r]=min(dp[l][r],dp[l][k]+4); else dp[l][r]=min(dp[l][r],dp[l][k]+3); } else dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]); } else dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]); } } } printf("%d\n",dp[1][len]); return 0; }