描述:
老鼠在某个城市储存了一些奶酪,城市可以看成一个 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.多条路的值比大小,确定节点的值,再慢慢退回起点
以样例数据为例:
序号为执行顺序。
代码参考了HDOJ水题集合7:记忆化搜索_how many ways 杭电-CSDN博客