POJ 1239 Increasing Sequences(两次DP)

Increasing Sequences

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
using namespace std;

#define Maxn 90
char sa[Maxn];
int dp[Maxn];

bool isgreater(int i, int j, int m, int n) { //判断从i~j的串是否大于从m~n的串
    while(sa[i] == '0' && i <= j)//去掉前导0
        i++;

    while(sa[m] == '0'&& m <= n )//去掉前导0
        m++;

    if(i > j) //前者为0
        return false;
    if(m > n) //后者为0
        return true;

    int a = j - i + 1, b = n - m + 1;//数字的长度,即数字的位数
    if(a > b)
        return true;
    else if(a < b)
        return false;
    else {
        for(int k = i, p = m; k <= j && p <= n; k++, p++) { //如果两个数字的位数相同,就逐位比较
            if(sa[k] > sa[p])//前一个数字大于后一个
                return true;
            else if(sa[k] < sa[p])//后一个数字大于前一个
                return false;
        }
    }

    return false; //等于的情况
}

int main() {
    freopen("data.in", "r", stdin);
    while(scanf("%s", sa+1) != EOF) { //字符串下标从1开始读入
        int n = strlen(sa+1);//字符串总长
        if(n == 1&& sa[1] == '0')
            break;

        dp[1] = 1;//dp[i]表示从第i位往前 共长度最小为dp[i]组成一个数字时的情况
        for(int i = 2; i <= n; i++) {
            dp[i] = i;
            for(int j = i-1; j >= 1; j--)
                if(isgreater(j+1, i, j-dp[j]+1, j)) {
                    dp[i] = i-j; //求出满足题意的最小长度,即最后一个数尽可能的小
                    break;//跳转到下一个i
                }
        }

        //然后从后往前,dp[i]表示在满足第一个条件的情况下,从i开始的最大长度
        int len = n - dp[n] + 1;//len表示原字符串中去掉最后一个数的第一个字符的位置
        dp[len] = dp[n];//最后一个数的长度
        for(int i = len-1; i >= 1; i--) {
            if(sa[i] == '0') { //数有前导0
                dp[i] = dp[i+1] + 1;//该数字长度再加上前导0的长度
                continue;
            }
            for(int j = len; j > i; j--)//求出长度最大的
                if(isgreater(j, j+dp[j]-1, i, j-1)) {
                    dp[i] = j-i;//使第一个数尽可能大
                    break;
                }
        }

        for(int i = 1; i <= dp[1]; i++) //输出第一个数字
            putchar(sa[i]);
        int t = dp[1] + 1;//第二个数字的起始位置

        while(t <= n) {
            putchar(',');
            for(int i = t; i < t+dp[t]; i++)
                printf("%c", sa[i]);

            t = t + dp[t];//转移到下一个数字的起始位置
        }

        putchar('\n');
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值