hduoj_1176 hduoj_2084 (dp,经典)

我最先看的是1176。

感觉自己做了一些dp题,有了些经验,就自己想了一会,敲了一份代码。

通过了样例,但是tle。

代码如下。

#include <stdio.h>
#include <math.h>
#include <string.h>

int dp[100000];

struct pie
{
	int second;
	int pos;
}pies[100000];

int main()
{
	int n, m;
	int i, j;
	int now;

	while (scanf("%d", &n) && n)
	{
		for (i = 1; i <= n; i++)
			scanf("%d %d", &pies[i].pos, &pies[i].second);
		
		memset(dp, 0, sizeof(dp));
		
		pies[0].pos = 5;
		pies[1].second = 1;
		for (i = 1; i <= n; i++)
		{
			for (j = 0; j < i; j++)
			{
				if (abs(pies[i].pos - pies[j].pos) <= abs(pies[i].second - pies[j].second))
				{
					if (dp[j] + 1 > dp[i])
						dp[i] = dp[j] + 1;
				}
			}
		}
		m = -1;
		for (i = 1; i <= n; i++)
			m = m > dp[i] ? m : dp[i];
		printf("%d\n", m);
	}
	return 0;
}

然后开始找题解。

发现这竟然是一道二维的dp。同时找到了 2084 这道题(数塔)。

思路也比较好理解。

AC代码如下。

#include <stdio.h>
#include <string.h>
                      // 0 1 2 3 4 5 6 7 8 9 10 11 12
int time[100001][13]; // _ 0 1 2 3 4 5 6 7 8 9  10  _

int max(int a, int b, int c)
{
	a = a > b ? a : b;
	a = a > c ? a : c;
	return a;
}

int main()
{
	int n;
	int x, T;
	int i, j;
	int t;
	while (scanf("%d", &n) && n)
	{
		memset(time, 0, sizeof(time));
		t = -1;
		for (i = 1; i <= n; i++)
		{
			scanf("%d %d", &x, &T);
			x++;
			time[T][x]++;
			t = t > T ? t : T;
		}

		for (i = t - 1; i >= 0; i--)
		{
			for (j = 1; j <= 11; j++)
				time[i][j] += max(time[i + 1][j - 1], time[i + 1][j], time[i + 1][j + 1]);
		}

		printf("%d\n", time[0][6]);
	}
	return 0;
}

这道题有一些问题。

time[100000][13]  WA

time[100001][13]  AC

但是题中给定的条件是

0<n<100000

0<T<100000

T最大是99999。

然后是2084数塔这道题。

一次AC。

#include <stdio.h>

int map[101][101];

int max(int a, int b)
{
	return a > b ? a : b;
}

int main()
{
	int C;
	int N;

	int i, j;

	scanf("%d", &C);
	while (C--)
	{
		scanf("%d", &N);
		for (i = 1; i <= N; i++)
		{
			for (j = 1; j <= i; j++)
				scanf("%d", &map[i][j]);
		}

		for (i = N - 1; i >= 1; i--)
		{
			for (j = 1; j <= i; j++)
			{
				map[i][j] += max(map[i + 1][j], map[i + 1][j + 1]);
			}
		}

		printf("%d\n", map[1][1]);
	}
	return 0;
}

上面的代码是自下而上dp的。

开了个脑洞,自上而下是否可以呢?

证明也可以。下面是AC代码。

#include <stdio.h>

int map[101][101];

int max(int a, int b)
{
	return a > b ? a : b;
}

int main()
{
	int C;
	int N;

	int i, j;
	int m;

	scanf("%d", &C);
	while (C--)
	{
		scanf("%d", &N);
		for (i = 1; i <= N; i++)
		{
			for (j = 1; j <= i; j++)
				scanf("%d", &map[i][j]);
		}

		for (i = 2; i <= N; i++)
		{
			map[i][1] += map[i - 1][1];
			for (j = 2; j <= i; j++)
			{
				map[i][j] += max(map[i - 1][j], map[i - 1][j - 1]);
			}
		}

		m = -1;
		for (i = 1; i <= N; i++)
			m = m > map[N][i] ? m : map[N][i];
		printf("%d\n", m);
	}
	return 0;
}

这题看起来更像是一个二维dp的特殊情况。

还有一个问题。1176馅饼那道题是否也可以自上而下dp呢(上面的代码是自下而上dp的)?

我认为是不可以。

因为题目中规定了起点5。自上而下的话,不能保证最大值的起点是5。

而数塔那道题只有一个起点。

点赞