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;
}
递归

 

posted @ 2018-06-06 15:47  Zinn  阅读(151)  评论(0编辑  收藏  举报