UVA - 1630 Folding 递归记忆化搜索

问题

问题就是折叠字符串,例如ACBACB可以折叠成2(ACB),并且折叠可以嵌套,字符串长度是n(1<n<=100),求最短的折叠

分析

状态比较易懂,dp[i][j]代表[i,j]这一段能压缩成的最短字符串
然后分为三种情况决策,1.不能压缩的 2.能部分压缩的(就是分开后再压缩) 3.整体能压缩的

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=105;
//int slen[maxn][maxn];
string dp[maxn][maxn],str;

//计算重复的最小长度
int fold(const string &s){
    int len=s.length();
    for(int i=1;i*2<=len;++i){
        if(len%i) continue;
        bool isFold=true;
        for(int j=0;j<len-i;++j){
            if(s[j]!=s[j+i]){
                isFold=false;
                break;
            }
        }
        if(isFold) return i;
    }
    return 0;
}

//折叠分为三种情况 1.不能折叠 2.部分折叠 3.整体都能折叠
int DFS(int left,int right){
    string &ans=dp[left][right];
    if(ans!="") return ans.length();
    if(left==right) {
        ans=str.substr(left,1);
        return ans.length();
    }
    //分开,处理1,2情况,不能折叠,部分折叠
    for(int i=left;i<right;++i){
        int t1=DFS(left,i),t2=DFS(i+1,right);
        if(ans.empty() || t1+t2<ans.length()){
            ans=dp[left][i]+dp[i+1][right];
        }
    }
    //处理情况三,整体折叠
    int t=fold(str.substr(left,right-left+1));
    if(t){
        string tstr=to_string((right-left+1)/t)+"("+dp[left][left+t-1]+")";
        if(ans.empty() || tstr.length()<ans.length()){
            ans=tstr;
        }
    }
    return ans.length();
}

int main(void){
    while(cin>>str){
//        memset(slen,-1,sizeof(slen));
        int len=str.length();
        for(int i=0;i<=len;++i){
            for(int j=0;j<=len;++j){
                dp[i][j]="";
            }
        }
        DFS(0,len-1);
        cout<<dp[0][len-1]<<endl;
    }
}

减少了字符串的变化,优化时间

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=105;
int slen[maxn][maxn];  //slen[left][right]是[left,right]压缩后的最小长度
string dp[maxn][maxn],str;

//计算重复的最小长度
int fold(const string &s){
    int len=s.length();
    for(int i=1;i*2<=len;++i){
        if(len%i) continue;
        bool isFold=true;
        for(int j=0;j<len-i;++j){
            if(s[j]!=s[j+i]){
                isFold=false;
                break;
            }
        }
        if(isFold) return i;
    }
    return 0;
}

//折叠分为三种情况 1.不能折叠 2.部分折叠 3.整体都能折叠
int DFS(int left,int right){
    int &ans=slen[left][right];
    if(ans>=0) return ans;
    string &ansstr=dp[left][right];
    if(left==right) {
        ans=1;
        ansstr=str.substr(left,1);
        return ans;
    }
    //分开,处理1,2情况,不能折叠,部分折叠
    int t=0;
    ans=100000;
    for(int i=left;i<right;++i){
        int t1=DFS(left,i),t2=DFS(i+1,right);
        if(t1+t2<ans){
            ans=t1+t2;
            t=i;
        }
    }
    ansstr=dp[left][t]+dp[t+1][right];
    //处理情况三,整体折叠
    t=fold(str.substr(left,right-left+1));
    if(t){
        string tstr=to_string((right-left+1)/t)+"("+dp[left][left+t-1]+")";
        if(tstr.length()<ans){
            ans=tstr.length();
            ansstr=tstr;
        }
    }
    return ans;
}

int main(void){
    while(cin>>str){
        memset(slen,-1,sizeof(slen));
        int len=str.length();
//        for(int i=0;i<=len;++i){
//            for(int j=0;j<=len;++j){
//                dp[i][j]="";
//            }
//        }
        DFS(0,len-1);
        cout<<dp[0][len-1]<<endl;
    }
}

发布了50 篇原创文章 · 获赞 0 · 访问量 713

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/104076155