POJ 2176 动态规划 区间DP

区间DP,需要学习的常用技巧是:不仅仅保存最优解的长度,还同时保存了最优解字符串,也就是说DP不仅仅是一个数组。对于i和j之间的字符,我们可以先尽量寻找他们的最小重复循环节,并且记录最小重复循环节的长度,也就得到了如果对整段进行压缩的最小长度,而后使用区间DP的中点枚举的思想,比较是直接将i到j进行压缩好,还是分开压缩好。

但是有一点需要额外注意,当发现了i-j可以直接压缩的时候,在括号里要填充dp[i][i+current_len-1].str,而不是str中i后长current_len的部分,因为可能存在嵌套压缩的情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node {
    int Len;
    char Str[110];
};
Node dp[110][110];
char str[110];
int L;
int main() {
    scanf("%s", str);
    L = strlen(str);
    for(int i = 1; i <= L; i ++) {
        dp[i][i].Len = 1;
        dp[i][i].Str[0] = str[i - 1];
    }
    for(int l = 2; l <= L; l ++) {
        for(int i = 1, j = i + l - 1; j <= L; i ++, j ++) {
            dp[i][j].Len = 10000;
            for(int k = 1; k <= l / 2; k ++) {
                if(l % k != 0) {
                    continue;
                }
                int s = i, t = i + k;
                while(t <= j && str[s - 1] == str[t - 1]) {
                    s ++;
                    t ++;
                }
                if(t > j) {
                    int ctr = l / k;
                    sprintf(dp[i][j].Str, "%d", ctr);
                    strcat(dp[i][j].Str, "(");
                    strcat(dp[i][j].Str, dp[i][i + k - 1].Str);
                    strcat(dp[i][j].Str, ")");
                    dp[i][j].Len = strlen(dp[i][j].Str);
                    break;
                }
            }
            for(int k = i; k < j; k ++) {
                if(dp[i][k].Len + dp[k + 1][j].Len <= dp[i][j].Len) {
                    dp[i][j].Len = dp[i][k].Len + dp[k + 1][j].Len;
                    strcpy(dp[i][j].Str, dp[i][k].Str);
                    strcat(dp[i][j].Str, dp[k + 1][j].Str);
                }
            }
        }
    }
    printf("%s\n", dp[1][L].Str);
}

 

转载于:https://my.oschina.net/fuchuanpu/blog/3051930

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值