UVA - 10913Walking on a Grid(记忆化搜索)

题目:Walking on a Grid

题目大意:给出N * N的矩阵,每个格子里都有一个值,现在要求从(1,1)走到(n, n),只能往下,左,右这三个方向走,并且要求最多只能取k个负数,求这样的要求下能得到的走过格子的值之和最大。

解题思路:记忆化搜索,但是这里要四维的,因为要记录方向,为了防止走回头的路,并且取了几个负数也要记录。然后就是dfs了。状态转移方程:dp【x】【y】【d】【k】 = dp【x + dir【i】【0】】【y + dir【i】【1】】【i】【k1] + G[x][y]; d代表从(x, y)出发走的方向。k:负数的个数(包括x,y这个格子走过的格子的负数总数),k1要根据G【x + dir【i】【0】】【y + dir【i】【1】】】来定,为正就还是等于k,为负就等于k  + 1;

发现初始化真心要小心。

代码:

#include <cstdio>
#include <cstring>

typedef long long ll;

const int N = 80;
const int M = 3;
const ll INF = 0x3f3f3f3f3f;
const int dir[M][2] = {{0, -1}, {1, 0}, {0, 1}};

int G[N][N];
ll dp[N][N][6][M];
int n, k;

ll Max (const ll a, const ll b) { return a > b ? a: b;}

void init () {

	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			for (int l = 0; l <= k; l++)
				for (int m = 0; m < M; m++)
					dp[i][j][l][m] = -INF;

	if (G[0][0] < 0)//一开始的(0,0)位置的值如果是负数的话,那么取负数的机会就被占用了一个。
		k--;
	for (int l = 0; l <= k; l++)
		for (int m = 0; m < M; m++)
			dp[n - 1][n - 1][l][m] = G[n - 1][n - 1];
}

ll DP (int x, int y, int d, int cnt) {

	int newx, newy;
	ll &ans = dp[x][y][cnt][d];
	if (ans != -INF)
		return ans;

	ll temp;
	if (d == 1) {//取下的话,那么三个方向都是可以取的

		for (int i = 0; i < M; i++) {

			newx = x + dir[i][0];
			newy = y + dir[i][1];
			if (newx < 0 || newx >= n || newy < 0 || newy >= n)
				continue;

			if (G[newx][newy] < 0 && cnt == k)
				continue;
			if (G[newx][newy] < 0 && cnt < k) {
				temp = DP(newx, newy, 2 - i, cnt + 1);
				if (temp != -INF - 1)
					ans = Max (ans, temp + G[x][y]);
			}
			if (G[newx][newy] >= 0) {
				temp = DP (newx, newy, 2 - i, cnt);
				if (temp != -INF - 1)
					ans = Max (ans, temp + G[x][y]);
			}
		}
	} else {//取左/右的话下次就不要取右/左。

		for (int i = (d + 1) % M; i != d; i = (i + 1) % M) {

			newx = x + dir[i][0];
			newy = y + dir[i][1];
			if (newx < 0 || newx >= n || newy < 0 || newy >= n)
				continue;

			if (G[newx][newy] < 0 && cnt == k)
				continue;
			if (G[newx][newy] < 0 && cnt < k) {
				temp = DP(newx, newy, 2 - i, cnt + 1);
				if (temp != -INF - 1)
					ans = Max (ans, temp + G[x][y]);
			}
			if (G[newx][newy] >= 0) {
				temp = DP (newx, newy, 2 - i, cnt);
				if (temp != -INF - 1)//当这个位置可以到的时候才计算
					ans = Max (ans, temp + G[x][y]);
			}
		}
	}

	if (ans == -INF)//代表以目前的要求不能到达这个格子
		ans = -INF - 1;
	return ans;
}

int main () {

	int cas = 0;
	while (scanf ("%d%d", &n, &k), n || k) {

		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				scanf ("%d", &G[i][j]);

		init ();

		ll ans;
		ans = DP(0, 0, 1, 0);

		printf ("Case %d:", ++cas);
		if (ans == -INF - 1)
			printf (" impossible\n");
		else
			printf (" %lld\n", ans);
	}
	return 0;
}

UVA - 10913Walking on a Grid(记忆化搜索)

时间: 2024-10-12 15:45:26

UVA - 10913Walking on a Grid(记忆化搜索)的相关文章

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

UVA 10981 - String Morphing(记忆化搜索)

题目链接:10981 - String Morphing 题意:给定开始的字符串,要求根据表格变化成一个字符串,问变化的顺序(注意,不一定要最少步数) 思路:记忆化搜索,用map来存字符串的状态,一开始按最少步数去做TLE,其实只要找到一个符合的就可以了 代码: #include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <map> u

UVA 1629 - Cake slicing(记忆化搜索)

记忆化搜索, 枚举所有的切割方式dp[r1][c1][r2][c2]表示(r1, c1) (r2, c2)之间的蛋糕切割所需要的最小花费count_num用来计算(r1, c1) (r2, c2)之间有多少个草莓递推边界当count_num为1是返回0 init()为对草莓数的一个预处理,使得在O(1)的时间内可以计算区域内的草莓数 总状态数为m * n * m * n决策有n + m种 时间复杂度为O((n + m) * n * n * m * m) /*583ms*/ 1 #include<

uva 10626 Buying Coke (DP + 记忆化搜索)

Problem D Buying Coke Input: Standard Input Output: Standard Output Time Limit: 2 Seconds I often buy Coca-Cola from the vending machine at work. Usually I buy several cokes at once, since my working mates also likes coke. A coke in the vending machi

UVa 10118 Free Candies (记忆化搜索+哈希)

题意:有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果,如果篮子里有两个相同的糖果, 那么就可以把这两个(一对)糖果放进自己的口袋里,问最多能拿走多少对糖果. 析:首先看到的是时间30s,这么长时间,一想应该是暴力了吧,后来一想应该是记忆化搜索,既然这么长时间,应该得优化一下,不然可能超时, 但是数据好像挺水,才运行了60ms,并不知道是怎么回事,接下来说说这个题,用 d[a,b,c,d] 来表示 分别从 第一,二,三,四堆拿的最多糖果, 如

UVa 10599【lis dp,记忆化搜索】

UVa 10599 题意: 给出r*c的网格,其中有些格子里面有垃圾,机器人从左上角移动到右下角,只能向右或向下移动.问机器人能清扫最多多少个含有垃圾的格子,有多少中方案,输出其中一种方案的格子编号.格子编号是从 左上角第一个开始,一行一行的按自然数顺序编.起始行列是第一行第一列.所以例如一个格子的行列号为(ro,co),那么它的编号为bh=(ro-1)*column+co,其中column指这个格子有多少列.(我觉得原题里面有个错误,题目叙述倒数第二行应该是41(6,6)不是41(6,7)).

UVa 674 Coin Change【记忆化搜索】

题意:给出1,5,10,25,50五种硬币,再给出n,问有多少种不同的方案能够凑齐n 自己写的时候写出来方案数老是更少(用的一维的) 后来搜题解发现,要用二维的来写 http://blog.csdn.net/keshuai19940722/article/details/11025971 这一篇说的是会有面值的重复问题,还不是很理解 还有就是一个预处理的问题, 看了题解之后再自己写,很习惯的把处理dp数组写到while循环里面,一直tle 后来看到这篇题解 http://www.cnblogs.

UVA - 10891 Game of Sum(记忆化搜索 dp)

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; int a[100+10]; int dp[120][120]; int sum[120]; int vis[120][120]; int dfs(int f,int t) { int i,j,k; if(vis[f][t]==