HDU 1978 How many ways

传送门

dfs记忆化搜索、动态规划。
是中文题,但是题意没说清楚,反正把我恶心到了。你是真的牛批。

两个地方没说清楚。

  1. 实际上每到一条路径终点之后就清除身上携带的能量值(若没用完),然后再加上这个路径终点的能量值。
    若按我理解的那样,则每个点的状态要用三维数组表示,其中第三维表示在当前点含有e能量值到终点的路数。可知当e>=N-x+M-y时的状态都等价。
  2. 这个题中说的总体路线是一条条路径组成的,它不关心每条路径的具体走法,它只关心每条路径的路径终点是什么。也就是说,总体路线是这样标识的:((1,1),路径终点,路径终点,。。。,路径终点,(N,M))。这个序列不同则路线不同,这个序列相同则路线相同。
    若按我理解的那样,每条路径还要计算有多少种走法,然后dp[x][y] += num[dx][dy]*dp[x+dx][y+dy]。(计算这个不难,dp转移式:num[dx][dy] = num[dx-1][dy]+num[dx][dy-1]dx,dy表示两点间的坐标差值)

然后再说几个注意的地方:

  1. 如果把dp的初始值设为0,则与计算出来dp真的等于0的那些值混淆了,这就意味着每次这些“真”0值都无法被记忆化了。所以我们设初始值都为-1,彻底区分未计算值和已计算值。(但这样的话,每次计算前别忘了先清零)
  2. 直接枚举增量,然后在第二层循环for内部直接判断dx+dy<=a[x][y],这样枚举的三角形斜边就出来了,很巧妙。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;

const int MOD = 10000;
const int MAX = 101;
int N, M, T;
int a[MAX][MAX];
//int num[MAX][MAX];                    // 没用了,人家不关心你是怎么走到下一跳的
int dp[MAX][MAX];

void init()
{
	//memset(num, 0, sizeof num);
	memset(dp, -1, sizeof dp);
}

//void run1()
//{
//	for (int i = 0; i < MAX; i++)
//		num[0][i] = num[i][0] = 1;
//	for (int i = 1; i <= N - 1; i++)
//		for (int j = 1; j <= M - 1; j++)
//			num[i][j] = num[i - 1][j] + num[i][j - 1];
//}

int run(int x, int y)
{
	if (x == N && y == M) return 1;
	if (dp[x][y] != -1) return dp[x][y];
	dp[x][y] = 0;                                     // 因为把初始值都弄成-1了,所以这里还要再清零
	for (int dx = 0; dx <= a[x][y]; dx++)
	{
		if (x + dx > N) break;                        // 之后的dx只会更大,所以可以退出循环了
		for (int dy = 0; dx + dy <= a[x][y]; dy++)    // 这里的限制条件提前到循环中判断,很巧妙
		{
			if (y + dy > M) break;
			if (dx == 0 && dy == 0) continue;
			dp[x][y] += run(x + dx, y + dy);          // 这里不用模
		}
	}
	return dp[x][y] %= MOD;                           // 这里的“=”别丢了,不然以后再引用的是原值
}

int main()
{
	scanf("%d", &T);
	for (; T--;)
	{
		scanf("%d%d", &N, &M);
		init();
		for (int i = 1; i <= N; i++)
			for (int j = 1; j <= M; j++)
				scanf("%d", &a[i][j]);
		
		//run1();
		printf("%d\n", run(1, 1));
	}

	return 0;
}
posted @ 2019-04-11 21:08  CrossingOver  阅读(108)  评论(0编辑  收藏  举报