ZOJ1499 POJ1239 HDU1511 Increasing Sequences

非常经典的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 : [email protected]
 # 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;

}


你可能感兴趣的:(ZOJ1499 POJ1239 HDU1511 Increasing Sequences)