非常经典的DP题!必须要好好研究!
需要两次dp,第一次dp正向,dp[i]的值x表示的是到了i,i前面的x个字符(包含i)组成数值后,前i个字符符合上升队列,且x为最大。则我们可以知道前i-dp[i]个也符合上升队列。
第一次dp求出符合题目要求的最后个数字的值为最小的值,注意这里说的是值而不是长度!因为对于如下测试数据
1234050
求出来符合要求的值是50,但是正确划分是
12,34,050
第二次dp为反向dp,求出符合题目要求的,第一个数字为最大的值,同时确定了这个值的长度!
第二次dp中的dp[i]的值为x,表示是到了i,i后面的x个字符(包含i)组成数字,i后面的所有字符符合上升队列,且x为最大。
第一次dp容易求,但是第二次dp因为数据中含有0,所以要分外小心,我就是在这里搞了很久,第二次一定要判断。
/*******************************************************************************
# Author : Neo Fung
# Email : neosfung@gmail.com
# Last modified: 2012-04-06 19:38
# Filename: ZOJ1499 POJ1239 HDU1511 Increasing Sequences.cpp
# Description :
******************************************************************************/
#ifdef _MSC_VER
#define DEBUG
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <limits.h>
#include <algorithm>
#include <math.h>
#include <numeric>
#include <functional>
#include <ctype.h>
#define MAX 100
using namespace std;
char num[MAX];
int dp[MAX],dprev[MAX];
int now[MAX],ans[MAX];
bool check( char *lhs,int n, char *rhs,int m)
{
char *p=lhs,*q=rhs;
while(*p=='0' && n)
{
++p;
--n;
}
while(*q=='0' && m)
{
++q;
--m;
}
if(n<m)
return true;
else if(n>m)
return false;
for(int i=0;i<n;++i)
if(*p<*q)
return true;
else if(*p>*q)
return false;
else
{
++p;
++q;
}
return false;
}
int main(void)
{
#ifdef DEBUG
freopen("../stdin.txt","r",stdin);
freopen("../stdout.txt","w",stdout);
#endif
int ncase=1;
// scanf("%d",&ncase);
while(gets(num+1))
{
int n=strlen(num+1)+1;
if(n==2 && num[1]=='0')
break;
num[0]='0';
memset(dp,0,sizeof(dp));
memset(now,0,sizeof(now));
dp[1]=1;
for(int i=2;i<n;++i)
{
dp[i]=i;
for(int j=i-1;j>0;--j)
{
int t=i-j;
if(check(num+j-dp[j]+1,dp[j],num+j+1,t))
{
dp[i]=t;
break;
}
}
}
int pos=n-1;
while(pos>0)
{
now[pos-dp[pos]+1]=dp[pos];
pos=pos-dp[pos];
}
int last=n-dp[n-1];
dp[last]=dp[n-1];
for(int i=last-1;i>0;--i)
{
dp[i]=-1;
if(num[i]=='0')
{
dp[i]=dp[i+1]+1;
continue;
}
for(int j=last;j>i;--j)
if(check(num+i,j-i,num+j,dp[j]))
{
dp[i]=j-i;
break;
}
}
pos=1;
memset(ans,0,sizeof(ans));
while(pos<n)
{
ans[pos]=1;
pos=pos+dp[pos];
}
for(int i=1;i<n;++i)
{
if(ans[i]&&i>1)
printf(",");
printf("%c",num[i]);
}
printf("\n");
}
return 0;
}