当前位置:   article > 正文

【递归+深搜+剪枝】详解+模板(不小心秒了三道题)_一个楼梯共有 n级台阶,每次可以走一级或者两级,问从第 0级台阶走到第 n级台阶一共

一个楼梯共有 n级台阶,每次可以走一级或者两级,问从第 0级台阶走到第 n级台阶一共

【递归+深搜+剪枝】详解+模板(不小心秒了三道题)

最近在开始恢复刷一些题,难度不是很大,康复训练了属于是。
今天偶然遇到三道类似的题,大概就是利用递归进行深度搜索,搜索的同时带一定的回溯剪枝来缩短搜索时长。ac掉第一道后,剩下两道稍微改了改也很神奇地秒掉了,所以想来记录一下,希望对大家有帮助。

Question1.跳台阶

一个楼梯共有 n 级台阶,每次可以走一级或者两级,问从第 0 级台阶走到第 n 级台阶一共有多少种方案。

输入格式

共一行,包含一个整数 n。

输出格式

共一行,包含一个整数,表示方案数。

数据范围

1≤n≤15

输入样例:
5
  • 1
输出样例:
8
  • 1
题解:

定义变量

cnt用来记录当前方案数
k代表当前已走的台阶数

搜索路径

走楼梯有1步\2步两种选择,因此有jump(n,k+1)和jump(n,k+2)两种递归方式

剪枝

若当前已走的台阶数>总共的台阶数(k>n),则剪枝,即return;

源代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int cnt = 0;  //记录当前方案数
void jump(int n,int k)
{
    if(k==n) cnt++;//若已到达终点,cnt++
    else if(k>n) return;//若当前已走的台阶数>总共的台阶数,则剪枝
    else //两种搜索路径
    {
        jump(n,k+1);
        jump(n,k+2);
    }   
}
int main()
{
    int n;
    cin>>n;
    jump(n,0);//从起点开始搜索
    cout<<cnt<<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
Question2.走方格

给定一个 n×m 的方格阵,沿着方格的边线走,从左上角 (0,0) 开始,每次只能往右或者往下走一个单位距离,问走到右下角 (n,m) 一共有多少种不同的走法。

输入格式

共一行,包含两个整数 n 和 m。

输出格式

共一行,包含一个整数,表示走法数量。

数据范围

1≤n,m≤10

输入样例:
2 3
  • 1
输出样例:
10
  • 1
题解:

定义变量

cnt用来记录当前方案数,k代表当前所在的行数,p代表当前所在的列数

搜索路径

走放个有往右或往下两种选择,因此有 walk(n,m,k+1,p)和walk(n,m,k,p+1)两种递归方式

剪枝

若当前行或列走出边界值(k>n || p>m),则剪枝,即return;

源代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int cnt = 0;
void walk(int n,int m,int k,int p)//递归深度搜索
{ 
    if(k==n && p==m) cnt++; //若已到达终点,cnt++
    else if(k>n || p>m) return; //若当前行或列走出边界值(k>n || p>m),则剪枝
    else //两种搜索路径
    {
        walk(n,m,k+1,p);
        walk(n,m,k,p+1);
    }   
}
int main()
{
    int n,m;
    cin>>n>>m;
    walk(n,m,0,0); //从(0,0)点开始走
    cout<<cnt<<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
Question3.排列

给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入格式

共一行,包含一个整数 n。

输出格式

按字典序输出所有排列方案,每个方案占一行。

数据范围

1≤n≤9

输入样例:
3
  • 1
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
题解:

定义变量

定义一个nums数组用于保存当前元素,is_visited数组用于记录当前元素是否被访问过,u记录当前已经存入nums的数的数量

搜索路径

只要is_visited为0即未被搜索过,就可以进行搜索,因此递归方式为Permutations(u+1,n,nums,is_visited);
注意:
递归之前要将 is_visited[i] 设为1,即在当前路径下设置已经访问过
并且递归过后一定要恢复现场!!
:将is_visited[i]再设为0,因为下次递归到这个数时为一条全新的路径

剪枝

因为nums定义时就只有n个,递归过程中也不存在超出范围的情况,本题无需剪枝。

源代码:
#include <iostream>
using namespace std;
void Permutations(int u,int n,int nums[],int is_visited[])//递归深度搜索
{
    if(u==n) //nums数组已满,到达终点,输出答案
    {
        for(int i =0;i<n;i++)
        {
            cout<<nums[i]<<" ";
        }
        cout<<endl;
    }
    else 
    {
        for(int i = 0;i<n;i++) //递归搜索时从头开始遍历
        {
            if(is_visited[i]==0) //未被访问过
                {
                    nums[u] = i+1; //存入当前数据
                    is_visited[i] = 1;//在当前路径下设置已经访问
                    Permutations(u+1,n,nums,is_visited);//递归搜索
                    is_visited[i] = 0;//恢复现场:为后面的路径设置未访问
                }
        }
    }   
}
int main()
{
    int n;
    cin>>n;
    int nums[n];
    int is_visited[n] = {0};
    Permutations(0,n,nums,is_visited);//从起点开始递归
    //cout<<ans<<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

最近才开始恢复刷一些题,没上很高的难度,有问题欢迎指正。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号