P8707题解

本文介绍了如何使用深度优先搜索解决一个二维数组问题,并通过记忆化搜索进行优化。作者详细解释了递归过程、边界条件处理以及记忆化数组在减少重复计算中的作用,最后提到了两个相关练习题目供读者进一步实践。
摘要由CSDN通过智能技术生成

原题链接: https://www.luogu.com.cn/problem/P8707

upt 2023/7/21 : 增加一些内容。
upt 2024/3/17 : 解答一些问题,删了一些废话。

第一阶段

我不会动态规划 dp,我只会 深度优先搜索 dfs。

我们先按二维数组的习惯构建坐标系。 ( x , y ) (x,y) (x,y) 表示第 x x x 行,第 y y y 列。

需注意边界处理。

  • 走到第 n n n 行第 m m m 列时,证明我们已经走到了终点,所以增加 1 1 1

  • 如果越界了,那么就不算。

  • 如果走到了题目中规定不走的格子,那么也不算。

注意 if 条件判断的顺序不能错哟。(请读者仔细考虑)

边界处理完后,我们看看怎么递归。

如果我们记 f x , y f_{x,y} fx,y 为点 ( x , y ) (x,y) (x,y) 到终点走法总数,依据题意可得

f x , y = f x + 1 , y + f x , y + 1 f_{x,y}=f_{x+1,y}+f_{x,y+1} fx,y=fx+1,y+fx,y+1

其中 f x + 1 , y f_{x+1,y} fx+1,y 表示 向下走一步后到终点走法总数 f x , y + 1 f_{x,y+1} fx,y+1 表示 向右走一步后到终点走法总数

如上所述递归即可。

#include <bits/extc++.h>
#define int long long

using namespace std;

int n,m;

int dfs(int x,int y){
    if(x>n||y>m) //如果越界了,那么就不算.
        return 0; 
    if(x==n&&y==m) 走到第 n 行第 m 列时,证明我们已经走到了终点,所以增加 1 .
        return 1;
    if((x%2==0)&&(y%2==0)) //如果走到了题目中规定不走的格子,那么也不算.
        return 0; //注意if的顺序不能错哟
    int ans=dfs(x+1,y)+dfs(x,y+1); //递归求解
    return ans; //返回答案
}

signed main(){
    cin>>n>>m;
    cout<<dfs(1,1);
}

建议读者仔细理解上面程序。

时间复杂度: 指数级别的。

第二阶段 (记忆化搜索)

关键词: 记忆化搜索

类似 P1048,我们也可以通过添加记忆化数组来优化算法。

#include <bits/stdc++.h>

using namespace std;

int n,m;
int mem[100][100]; //记忆化

int dfs(int x,int y){
    if(x>n||y>m)
        return 0;
    if(x==n&&y==m)
        return 1;
    if((x%2==0)&&(y%2==0))
        return 0;
    if(mem[x][y]!=-1)
        return mem[x][y];
    int ans=dfs(x+1,y)+dfs(x,y+1);
    return mem[x][y]=ans;
}

signed main(){
    memset(mem,-1,sizeof(mem)); //记得清空为-1
    cin>>n>>m;
    cout<<dfs(1,1);
}

这样我们就 A 了这道难(shui)题,哈哈!

时间复杂度: O ( n m ) O(nm) O(nm)。(每个函数调用只访问了一次)

问题&解答

Q chuiniudawang:return mem[x][y]=ans; 的作用是什么,为什么不直接return ans;

A da_ke:return mem[x][y]=ans; 的作用是先 mem[x][y]=ans,再 return mem[x][y];若直接 return ans; 则相当于没有「记忆化」,会超时。

Q xyx2002:时间超出了。

A da_ke:如果你提交第一份当然会超时,因为它没有剪枝。设想一下,第一份代码就是普通的 DFS,复杂度自然是指数级别的。

总结

这道题让我们学会了 记忆化搜索 这个法宝。用记忆化搜索会使代码比递推自然。

记忆化的关键是要大胆搜索,小心判断边界。

做完这道题请你尝试:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值