bzoj1090 [SCOI2003]字符串折叠——区间DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1090
区间DP...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,ans,dp[105][105]; char c[105]; bool pd(int l1,int r1,int l2,int r2) { int k1=r1-l1+1,k2=r2-l2+1; if(k1%k2)return 0;//前一个区间较长 for(int i=0;i<k1;i++) if(c[l1+i]!=c[l2+i%k2])return 0; return 1; } int cal(int x) { int ret=0; while(x)ret++,x/=10; return ret; } int main() { cin>>c; n=strlen(c); for(int i=0;i<n;i++) for(int j=0;j<n;j++) dp[i][j]=j-i+1; for(int len=2;len<=n;len++) for(int l=0;l+len<n;l++) { int r=l+len; for(int k=l;k<r;k++) { dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]); if(pd(k+1,r,l,k))dp[l][r]=min(dp[l][r],dp[l][k]+2+cal((r-k)/(k-l+1)+1));//纯折叠 //以l~k为一个循环节,注意不要除反了 } } printf("%d",dp[0][n-1]); return 0; }
还有递归版:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[101]; int f[101][101]; bool mark[101][101]; bool pd(int l1,int r1,int l2,int r2) { int k1=r1-l1+1,k2=r2-l2+1; if(k1%k2)return 0;//前一个区间较长 for(int i=0;i<k1;i++) if(s[l1+i]!=s[l2+i%k2])return 0; return 1; } int cal(int x) { int ret=0; while(x)ret++,x/=10; return ret; } int dp(int l,int r) { if(l==r)return 1; if(mark[l][r])return f[l][r]; mark[l][r]=1; int t=r-l+1; for(int i=l;i<r;i++) { t=min(t,dp(l,i)+dp(i+1,r)); if(pd(l,i,i+1,r))t=min(t,dp(l,i)+2+cal((i-l+1)/(r-i)+1)); } return f[l][r]=t; } int main() { cin>>s; printf("%d",dp(0,strlen(s)-1)); return 0; }