老鼠和奶酪dfs+DP题解

描述:

老鼠在某个城市储存了一些奶酪,城市可以看成一个 n*n 的网格,在每个网格的洞里,老鼠存储了 0~100 块的奶酪。

现在,小老鼠准备享用这些美味啦。

开始它在 (0, 0) 的位置,每吃光一个地方的奶酪,就转移到边上水平或者垂直的位置。麻烦的是,有只猫在洞的附近,所以它每次在被猫抓住之前最多只能移动 k 个位置,更糟糕的是,每吃掉一个地方的奶酪,就会变胖。所以,为了下一次逃跑有足够的能量,每次它必须移动到一个比这次有更多奶酪的网格。

现在已知 n 和 k,以及在每个网格的洞中小老鼠储存的奶酪的数量,请计算小老鼠在无法移动之前,一共最多能吃到多少块奶酪。

输入:

输入包含多组测试数据。

每组测试数据第一行包含 2 个正整数 n 和 k(0 < n, k <= 100)。接下来 n 行,每行包含 n 个数,分别表示每个网格中奶酪的数量。

输入数据以两个 -1 结束。

输出:

对于每组测试数据,请输出小老鼠最多能够吃到的奶酪数量。

每组数据输出一行。

输入样例 1 

3 1
1 2 5
10 11 6
12 12 7
-1 -1

输出样例 1

37

本题:DP+dfs

采用了记忆化搜索,是DP的一种方法

AC代码: 

#include <bits/stdc++.h>
using namespace std;
int n,k;
int f[104][104];
int mp[104][104];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int dfs(int x,int y){
//	if(x<0||x>=n||y<0||y>=n)  return;
	if(f[x][y]!=0)  return f[x][y];     //记忆化搜索 
	f[x][y]=mp[x][y];
	for(int j = 1;j<=k;j++){
		for(int i = 0;i<4;i++){
			int nx = x+dir[i][0]*j;  //记得要乘以j 
			int ny = y+dir[i][1]*j;
			if(nx>=0&&nx<n&&ny>=0&&ny<n&&mp[nx][ny]>mp[x][y]){  //顺序!!判断nx等等是否越界要放在前面,不然mp[nx][ny] 可能会直接访问一个非法内存区域,从而引发 runtime error 
				f[x][y] = max(f[x][y],mp[x][y]+dfs(nx,ny));
			}
		}
	}
	return f[x][y];   //注意最后一个return,返回结果 
}
int main(){
	while (cin>> n >>k){
		if (n==-1&&k==-1) break;
		memset(f,0,sizeof(f));
		memset(mp,0,sizeof(mp));
		for(int i = 0;i<n;i++){
			for(int j= 0;j<n;j++){
				cin >> mp[i][j];
			}
		}
		printf("%d\n",dfs(0,0));
	}
	return 0;
}

 

特别注意🔔

if(nx>=0&&nx<n&&ny>=0&&ny<n&&mp[nx][ny]>mp[x][y])

这句代码,判断nx等等是否越界要放在前面,不然mp[nx][ny] 可能会直接访问一个非法内存区域,从而引发 runtime error 

 

我通过debug,一步一步地看了代码实际运行过程:

1.找出所有能走的路

2.多条路的值比大小,确定节点的值,再慢慢退回起点

以样例数据为例:

2667f9e42d524cc5b3e170d931528219.jpeg

序号为执行顺序。

 

代码参考了HDOJ水题集合7:记忆化搜索_how many ways 杭电-CSDN博客

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值