UVa1630,Folding

区间dp,记忆化搜就可以

st为原串

dp[p][q]存st[p]~st[q]的最优长度,f[p][q]存对应的最优串

从(0,len-1)开始搜,f[0][len-1]为所求ans,回溯条件为p==q

同前两个题思路极为类似,但是我发现这3个题放到一起真的非常的好,难度递进,依次难在地方就是状态转移的时候决策的寻找

而此题的决策不是很明确,可以理解为两个决策吧(大家都这么认为= =但我不怎么赞同)

1:当子串st[p~q]可以折叠

2:将st[p~q]分成两段

二者中取最短

(其实第二个决策隐藏了一个决策,举个例子,原串AA,而压缩成2(A)显然是不对的,根据第二个决策,dp[AA]=dp[A]+dp[A]=2优于决策1)

自己coding时遇到一个问题:

NTTTTTNTTTTTNTTTTT

根据决策2,会得到一种情况f[0][len-1]=2(N5(T))N5(T),怎么折叠成3(N5(T));

若是根据决策1,那得到的结果会是3(NTTTTT);

特殊处理嵌套会非常麻烦

解决方法详见代码

观察了网上其他人的代码,学到了不少东西

coding+debug:差不多断断续续5个小时左右(但是这5个小时是比较值的,记忆化dp或者说区间dp这一方面我理解的更具体,更深刻了)

/*
 * Author:  Bingo
 * Created Time:  2015/3/3 14:19:57
 * File Name: uva1630.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
using namespace std;
const int maxint = 1000000;
int n;
int len;
string st;
int dp[150][150];
string f[150][150];//一层状态对应一个串
int judge(int l,int r){ 
    for(int i=1;i<=(r-l+1)/2;i++){  
        if((r-l+1)%i)continue;  
        bool flag=true;  
        for(int j=l;j+i<=r;j++){  
            if(st[j]!=st[j+i]){  
                flag=false;  
                break;  
            }  
        }  
        if(flag)return i;  
    }  
    return false;  
}  
int solve(int p,int q){
    if (dp[p][q]) return dp[p][q];
    else if(p==q) {
        f[p][q]=st[p];
        dp[p][q]=1;
        return 1;
    }
    else {
        int ans=maxint;
        int res;
        int k;
        for (int i=p;i<q;i++){
            res=solve(p,i)+solve(i+1,q);
            if (ans>res){
                ans=res;
                k=i;
            }
        }
        f[p][q]=f[p][k]+f[k+1][q];//此时的f[p][q]是否可折叠等价于st[p] [q]是否可折叠,巧妙的解决折叠f[p][q]时提取公因式的困难 
        int t=judge(p,q);
        if (t){
            char tt[10];
            sprintf(tt,"%d",(q-p+1)/t);
            string newstr=tt+string("(")+f[p][p+t-1]+string(")");//f[p][p+t-1]是精髓所在 
            if (newstr.size()<f[p][q].size()) f[p][q]=newstr;
        } 
        dp[p][q]=f[p][q].size();
        return dp[p][q];
    }
}
int main () {
    while (cin>>st){
        len=st.size();
        memset(dp,0,sizeof(dp));
        solve(0,len-1);
        cout << f[0][len-1]<<endl;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/acbingo/p/4312968.html