poj1239 Increasing Sequences

题意:用逗号划分数字串,使最后一个子串最小,且开头的子串尽可能大。

方法:

两次DP

1. 求出最后一个子串的值

状态:从前向后DP,dp[i]代表在0~i的子串中,dp[i]~i所代表的子串是最小的最后子串。

转移:枚举dp[i]的值由j-1~0,如果dp[i]~i所代表的子串比dp[i-1]~i-1的子串所代表的值大,则dp[i]~i是最小的最后子串。

2. 求出题目要求的序列

状态:从后向前DP,dp[i]代表在i~len-1的子串中,i~dp[i]所代表的子串是最大的第一个子串。

转移:枚举dp[i]的值由i~len-1,如果i~dp[i]所代表的子串比dp[i]+1~dp[dp[i]+1]的子串大,则可增大dp[i]的值选择更大的第一子串。

以上转自http://blog.csdn.net/cyberzhg/article/details/7538304

/**
 * Problem:POJ1239
 * Author:Shun Yao
 * Time:2013.5.20
 * Result:Accepted
 * Memo:DP
 */

#include <cstring>
#include <cstdlib>
#include <cstdio>

using namespace std;

const long Maxn = 88;

long n, N, minl[Maxn], maxl[Maxn];
char s[Maxn];

long compare(char *s1, char *e1, char *s2, char *e2) {
	while (*s1 == '0' && s1 != e1)
		++s1;
	while (*s2 == '0' && s2 != e2)
		++s2;
	static long l1, l2;
	l1 = e1 - s1;
	l2 = e2 - s2;
	if (l1 != l2)
		return l1 - l2;
	while (s1 != e1) {
		if (*s1 != *s2)
			return *s1 - *s2;
		++s1;
		++s2;
	}
	return 0;
}

int main() {
	static long i, j;
	freopen("poj1239.in", "r", stdin);
	freopen("poj1239.out", "w", stdout);
	while(scanf(" %s", s), strcmp(s, "0")) {
		n = strlen(s);
		memset(minl, 0, sizeof minl);
		for (i = 1; i < n; ++i)
			for (j = i - 1; j >= 0; --j)
				if (compare(s + minl[j], s + j + 1, s + j + 1, s + i + 1) < 0) {
					minl[i] = j + 1;
					break;
				}
		memset(maxl, 0, sizeof maxl);
		N = minl[n - 1];
		maxl[N] = n - 1;
		for (i = N - 1; i >= 0 && s[i] == '0'; --i)
			maxl[i] = n - 1;
		for (; i >= 0; --i)
			for (j = N - 1; j >= i; --j)
				if (compare(s + i, s + j + 1, s + j + 1, s + maxl[j + 1] + 1) < 0) {
					maxl[i] = j;
					break;
				}
		for (i = 0, j = maxl[i]; i < n; j = maxl[j + 1]) {
			if (i)
				putchar(',');
			while (i < n && i <= j)
				printf("%c", s[i++]);
		}
		putchar('\n');
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}


作者:HSUPPR
出处:http://www.cnblogs.com/hsuppr/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/hsuppr/p/3088320.html