递增序列

递增序列

时间限制: 1 Sec  内存限制: 128 MB

题目描述

给定一个数字串,请你插入若干个逗号,使得该数字串成为一个严格递增的数列且最后一个数要尽可能小,在这个问题中,前导的零是允许出现在数的前面的。

 

输入

输入数据仅含一行,为一个长度不超过 80 的数字串。

 

输出

输出一个严格递增且最后一数最小的数列,相邻两个数之间用一个逗号隔开,如果有多个数列满足要求,则输出第一个数最大的那个数列,若这样的解还不止一个,则输出第二个数最大的那个数列,以此类推。

 

样例输入

100000101

样例输出

100,000101
题解:
dp[i]表示i位以前所有分法中能使最后一个数最小的最后一个数的下标,f[i]表示从后往前能使最前面一个数最大的最前面一个数的下标。
先动归dp[i],保证最后一个数最小,再动归f[i],保证前面的数最大。由此而来即是最优解。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
using namespace std;
int n,dp[120],f[120],ans[120],cnt;
char s[120];
int cmp(int l,int r,int ll,int rr)
{
    while(s[l]=='0'&&l+1<=r)l++;
    while(s[ll]=='0'&&ll+1<=rr)ll++;
    int len1=r-l+1,len2=rr-ll+1;
    if(len1>len2)return 1;
    else if(len1<len2)return -1;
    else
    {
        while(l+1<=r&&ll+1<=rr&&s[l]==s[ll])
        {
            l++;
            ll++;
        }
        if(s[l]>s[ll])return 1;
        if(s[l]<s[ll])return -1;
    }
    return 0;
}
int main()
{
    int i,j;
    scanf("%s",s);
    n=strlen(s);
    dp[0]=0;
    for(i=1; i<n; i++)
    {
        for(j=i-1; j>=0; j--)
        {
            if(cmp(dp[j],j,j+1,i)<0)
            {
                dp[i]=j+1;
                break;
            }
        }
    }
    f[dp[n-1]]=n-1;
    int k=dp[n-1]-1;
    while(s[k]=='0')
    {
        f[k]=n-1;
        k--;
    }
    for(i=k; i>=0; i--)
    {
        for(j=dp[n-1]; j>=i+1; j--)
        {
            if(cmp(i,j-1,j,f[j])<0)
            {
                f[i]=j-1;
                break;
            }
        }
    }
    i=0;
    while(1)
    {
        int l=i;
        i=f[i];
        for(j=l;j<=i;j++)
        cout<<s[j];
        i++;
        if(i==n)break;
        cout<<',';
        
    }
    return 0;
}

 

posted @ 2017-06-13 12:45  kakakakakaka  阅读(1023)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效