POJ 1239 Increasing Sequences

        题意:给定一个字符串,要求用逗号进行分割成连续上升的序列,使得最后一个值最小,如果有多种方案,则使得第一个最大,如果还有则使第二个最大,以此类推。

        首先我们可以用贪心的方法,用dp1[i]表示第i位作为当前数字的末位,使得最后一个值最小的方案的位置,那么转移就是i到1枚举j,如果[j,i]的数字大于[dp[j-1],j-1],那么当前[j,i]的数字就是dp[i]的答案了,因为位数更大答案不会更优。

        在求出了dp1[n]之后,我们就可以是的最后一个值最小了,假设为[pos,n]构成的数字最小,那我们再用dp2[i]表示第i个数字作为当前数字的第一位,所能构成的最大数字,同样从pos-1开始向前枚举j,如果[i,j]的数字小于[j+1,dp[j+1]]那么当前的数字肯定是最大的,从贪心的角度来看,这样选肯定更优,因为都是i开头,数字越长答案不会更差。在这里要注意,由于写法的原因,直接由dp1[n]的得到的pos是没有去除前导零的,如果有类似0001的数字,会将000与1分开,这样就不正确了,所以要从从dp1[n]的得到的pos一路向前枚举到不是0的位置,将它们的dp2更新为n即可。

       下附AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 85
using namespace std;
int len;
char s[maxn];
int dp1[maxn],dp2[maxn];
int judge(int l1,int r1,int l2,int r2)
{
	while(l1<r1 && s[l1]=='0') l1++;
	while(l2<r2 && s[l2]=='0') l2++;
	if(r1-l1!=r2-l2) return r2-l2>r1-l1;
	if(r1-l1==0)  	 return s[l2]>s[l1];
	for(int i=l1;i<=r1;i++)
	{
		int j=l2+i-l1;
		if(s[j]!=s[i]) return s[j]>s[i];
	}
	return false;
}
int main()
{
	while(~scanf("%s",s+1))
	{
		len=strlen(s+1);
		if(len==1 && s[1]=='0') return 0;
		dp1[1]=1;
		for(int i=2;i<=len;i++)
		{
			dp1[i]=1;
			for(int j=i-1;j>=1;j--)
			if(judge(dp1[j],j,j+1,i))
			{
				dp1[i]=j+1;
				break;
			}
		}
		
		int pos=dp1[len];
		dp2[pos]=len;
		int i;
		for(i=pos-1;i>=1 && s[i]=='0';i--)
		dp2[i]=len;
		for(;i>=1;i--)
		{
			dp2[i]=len;
			for(int j=pos-1;j>=i;j--)
			{
				if(judge(i,j,j+1,dp2[j+1]))
				{
					dp2[i]=j;
					break;
				}
			}
		}
		
		int flag=0;
		for(int i=1;i<=len;i++)
		{
			if(!flag) flag=true;
			else printf(",");
			for(int j=i;j<=dp2[i];j++)
			printf("%c",s[j]);
			i=dp2[i];
		}
		printf("\n");
	}
} 


         

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值