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;

}

 

你可能感兴趣的:(sequence)