P2437 蜜蜂路线【暴搜 + 记忆化搜 + DP】

😊😊 😊😊
不求点赞,只求耐心看完,指出您的疑惑和写的不好的地方,谢谢您。本人会及时更正感谢。希望看完后能帮助您理解算法的本质
😊😊 😊😊

蜜蜂路线

题目背景

题目描述

一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房 m m m 开始爬到蜂房 n n n m < n m<n m<n,有多少种爬行路线?(备注:题面有误,右上角应为 n − 1 n-1 n1

输入格式

输入 m , n m,n m,n 的值

输出格式

爬行有多少种路线

样例 #1

样例输入 #1

1 14

样例输出 #1

377

提示

对于100%的数据, 1 ≤ M , N ≤ 1000 1 \le M,N\le 1000 1M,N1000

小白到进阶各种解法:

一、暴搜:😊

在这里插入图片描述

思路:

  1. 递归的出口:走到 n n n 的时候。
  2. 关键在于递归的计算,很多同学会以为是一个二维的矩阵上递归搜索,实际不然,可以抽象成一个一维的序列来走,即之前的爬楼梯一样的,每次可以走一步,也可以走两步!

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 1e3 + 10;
int n, m;
int dx[] = {0,-1};
int dy[] = {1, 0};
int cnt;
void dfs (int u)
{
    if (u == n)
    {
        cnt ++;
        return;
    }
    
    if (u+1 <= n)   //+1 == 向下走!
        dfs (u+1);
    if (u+2 <= n)   //+2 == 向右走!
        dfs (u+2);
}

int main()
{
    cin >> m >> n;
    dfs (m);
    cout << cnt << endl;
    return 0;
}

在这里插入图片描述

二、记忆化搜索:😊

在这里插入图片描述

思路:

  1. 记忆化数组: f [ i ] f[i] f[i]表示从点 i i i 到点 n n n 的方案数!
  2. 又有个坑:请看下面的代码:
    请问我们初始的时候, f 数组 = − 1 f数组=-1 f数组=1,那么就不能在第一个 i f if if判断的递归里面写 f [ u ] + = d f s ( u + 1 ) f[u]+=dfs(u+1) f[u]+=dfs(u+1),计算错误,造成很大的误差!
  3. 如果初始化为: m e m s e t ( f , 0 , s i z e o f ( f ) ) ; memset (f, 0, sizeof(f)); memset(f,0,sizeof(f)); 则这么写: f [ u ] + = d f s ( u + 1 ) f[u]+=dfs(u+1) f[u]+=dfs(u+1) 没有任何问题!
if (u+1 <= n) f[u] = dfs(u+1);
if (u+2 <= n) f[u] += dfs(u+2);

memset (f, -1, sizeof(f));

代码:缺个高精度,暂时未学,学了就补上!

#include<iostream>
#include<cstring>

using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;

int dfs (int u)
{
	if (f[u] != -1) return f[u];
	if (u == n){
		f[u] = 1;
		return f[u];
	}
	if (u+1 <= n)
	    f[u] = dfs(u+1);
	if (u+2 <= n)
	    f[u] += dfs(u+2);
	return f[u];
}

int main()
{
    memset (f, -1, sizeof(f));
    cin >> m >> n;
    cout << dfs (m) << endl;
    return 0;
}

在这里插入图片描述

三、本题考察算法:😊

思路:

  1. 从子问题记录到原问题,请问求出 f [ n ] f[n] f[n]需要什么?

  2. 由图中的二维矩阵我们可以看出 +1 是往右走,+2 是往下走的,且由于每次只能从标号小的地方往标号大的地方走,所以到达终点 n n n 可以由 n − 1  或  n − 2 n-1\ 或\ n-2 n1  n2转移过来!

  3. f [ i ] f[i] f[i] 表示从起点 m m m 到达终点 i i i 的所有方案。所以说可得:
    f [ i ] = f [ i − 1 ] + f [ i − 2 ] ; \\f[i] = f[i-1] + f[i-2]; f[i]=f[i1]+f[i2]

  4. 记得初始化,因为: f [ 1 ] , f [ 0 ] f[1],f[0] f[1],f[0]不能递推!

代码:

#include<iostream>

using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;

int main()
{
    cin >> m >> n;
    //初始化:
    f[1] = 1;
    for (int i=2; i <= n; i ++)
		f[i] = f[i-1] + f[i-2];
    cout << f[n];
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值