H - Increasing Sequences POJ - 1239 (dp好题)

H - Increasing Sequences POJ - 1239

Given a string of digits, insert commas to create a sequence of strictly increasing numbers so as to minimize the magnitude of the last number. For this problem, leading zeros are allowed in front of a number. 

Input

Input will consist of multiple test cases. Each case will consist of one line, containing a string of digits of maximum length 80. A line consisting of a single 0 terminates input. 

Output

For each instance, output the comma separated strictly increasing sequence, with no spaces between commas or numbers. If there are several such sequences, pick the one which has the largest first value;if there's a tie, the largest second number, etc. 

Sample Input

3456
3546
3526
0001
100000101
0

Sample Output

3,4,5,6
35,46
3,5,26
0001
100,000101

题意:把一个序列分成多个序列,输出最后一个序列的值最小的情况,有多种情况下,保证前面的序列的值较大

思路:两次dp,第一次dp[i]=j表示最后一个数为【j,j+1,……i】,i从小到大遍历(从前往后),每次遍历得到的dp[i]值都是可以保证递增情况下,【j,j+1,……i】尽量小,出现,求出的dp[len-1]=j(len为序列长度)即为最后一个数的值最小的情况的第一个字符的下标。

第一次dp的意义仅是求得保证递增情况下最后一个数的最小值的情况。

第二次dp从最后一个数开始,在保证后面一个数比前面一个数大的情况下,使前一个数尽可能的大

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 88
#define nmax 6
char s[N];
int dp[N];
bool judge(int lx,int ly,int rx,int ry)
{
    while(s[lx]=='0') lx++;
    while(s[rx]=='0') rx++;
    int llen=ly-lx+1;
    int rlen=ry-rx+1;
    if(llen>rlen)
        return false;
    if(llen<rlen)
        return true;
    while(lx<=ly)
    {
        if(s[lx]<s[rx])
            return true;
        if(s[lx]>s[rx])
            return false;
        lx++;
        rx++;
    }
    return false;
}
int main()
{
    while(scanf("%s",s))
    {
        memset(dp,0,sizeof(dp));
        int len=strlen(s);
        if(len==1&&s[0]=='0')
            break;
        for(int i=1; i<len; i++)
        {
            for(int j=i-1; j>=0; j--) 
            {
  /*最后一个数的长度呈递增的顺序遍历(保证最后一个数尽可能小),
一定符合judge()成立,即保存最后一个数的情况。
*/
                if(judge(dp[j],j,j+1,i))
                {
                    dp[i]=j+1;
                    break;
                }
            }
        }
        int last=dp[len-1]-1;  
        dp[last+1]=len-1;
//除了dp[len-1]对第二次dp有影响,前面dp的结果对后面dp的结果都没影响。
        for(int i=last; i>=0; i--)
        {//求从i开始,保证递增的情况下,dp[i]的值尽可能靠后(即尽可能大)
            if(s[i]=='0')
            {  //特殊情况,dp[i]的值直接为后面一个字符的dp[i+1]的值
                dp[i]=dp[i+1];
                continue;
            }
            for(int j=last+1; j>i; j--)
            {  //第一个数的最后一个字符的下标尽可能靠后
                if(judge(i,j-1,j,dp[j]))
                {
                    dp[i]=j-1;
                    break;
                }
            }
        }
        for(int i=0; i<=dp[0]; i++)
            printf("%c",s[i]);
        int k=dp[0]+1;
        while(k<len)
        {
            printf(",");
            for(int i=k; i<=dp[k]; i++)
                printf("%c",s[i]);
            k=dp[k]+1;
        }
        printf("\n");
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值