bzoj1090(区间dp)
Description
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则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。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
读了半天才懂题目,原来求最短折叠长度是求2(NEERC3(YES))这个字符串的长
那么就很简单了
一个区间dp模型
dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r])
当s[l...i]为s[i+1...r]子串时就dp[l][r]=min(dp[l][r],dp[l][k]+2+calc((r-l+1)/(k-l+1)))
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=200; char S[maxn],s[maxn]; int dp[maxn][maxn]; bool mark[maxn][maxn]; bool judge(int l,int r,int cl,int cr){ if((cr-cl+1)%(r-l+1)) return false; //printf("%d ",cl+i); if(s[cl]!=s[l]) return false; for (int i=1;i<=cr-cl;i++){ if(s[cl+i]!=s[l+i%(r-l+1)]) return false; } return true; } int calc(int x){ int num=0; while(x){ num++; x/=10; } return num; } int dfs(int l,int r){ if(l==r) return 1; if(mark[l][r]) return dp[l][r]; mark[l][r]=1; int t=(r-l+1); for (int i=l;i<r;i++){ t=min(t,dfs(l,i)+dfs(i+1,r)); if(judge(l,i,i+1,r)){ t=min(t,dfs(l,i)+2+calc((r-i)/(i-l+1)+1)); } } return dp[l][r]=t; } int main(){ int len; scanf("%s",S); len=strlen(S); for (int i=0;i<len;i++) s[i+1]=S[i]; //printf("%d",len); printf("%d\n",dfs(1,len)); return 0; }