【数据结构题集】深度优先搜索算法(DFS)+vector容器的使用+pair工具使用---迷宫可行路径数、指定步数的迷宫问题、迷宫问题、矩阵最大权值以及路径问题、迷宫最大权值

   本篇文章有一些知识点,需要提前了解,这些原理都能搜到,也很好理解,玛卡不在此赘述了~

①DFS算法是什么,递归可以更好地实现深度优先算法,举例Fibonacci数列,更细分到底层,F(0) F(1)可以看成死胡同,使用栈来实现。 

②矩阵类问题 需要用到vector容器、pair工具以及其头文件,内部的函数如push_back等

①迷宫可行路径数(最基本迷宫问题、矩阵移动问题)

题目描述

       现有一个n∗m大小的迷宫,其中1表示不可通过的墙壁,0表示平地。每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。求从迷宫左上角到右下角的所有可行路径的条数。

输入描述

    第一行两个整数n​​​、m​​​(2≤n≤5,2≤m≤5​​​),分别表示迷宫的行数和列数;

    接下来n​行,每行m​个整数(值为01),表示迷宫。

输出描述

    一个整数,表示可行路径的条数。

样例1

输入

   3 3

   0 0 0

   0 1 0

   0 0 0

输出 

    2

分析

假设左上角坐标是(1,1)​,行数增加的方向为x​增长的方向,列数增加的方向为y​增长的方向。

可以得到从左上角到右下角有两条路径:

  1. (1,1)​​​=>(1,2)​​​=>(1,3)​​​=>(2,3)​​​=>(3,3)​​​
  2. (1,1)​=>(2,1)​=>(3,1)​=>(3,2)​=>(3,3)​​​

  初始visited[][]全为True,表示未经过的格子。通过DFS()迭代操作,进行上下右左四种操作,每移动一格进行isValid()判断是否符合标准,符合则将 visited[][]该格子改为False。达到终点则路径数counter加一。

#include <cstdio>

const int MAXN = 5;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int counter = 0;

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};//指出四种移动方式,上下右左
int dy[MAXD] = {1, -1, 0, 0};

bool isValid(int x, int y) {     //判断某点是否超出地图,验证合法性
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !visited[x][y];
}

void DFS(int x, int y) {
    if (x == n - 1 && y == m - 1) {  /*到达边界则将路径+1,通过下面的迭代出
                                                      来的数据反复进行操作*/
        counter++;
        return;
    }
    visited[x][y] = true;             //未被走过为True,走过为Flase
    for (int i = 0; i < MAXD; i++) {  //用dx[]dy[]来实现上下右左移动操作
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (isValid(nextX, nextY)) {   /*移动后的位置若合法且可通过,则继续进行移动操作
                                           通过迭代实现*/
            DFS(nextX, nextY);
        }
    }
    visited[x][y] = false;
}

int main() {
    scanf("%d%d", &n, &m);            //先完成输入数据操作
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);  
        }
    } 
    DFS(0, 0);                       //执行DFS(),即左上端点为起点
    printf("%d", counter);
    return 0;
}

② 指定步数的迷宫问题

  题目描述

现有一个n∗m大小的迷宫,其中1表示不可通过的墙壁,0表示平地。每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。现从迷宫左上角出发,问能否在恰好第k步时到达右下角。

 输入描述

       第一行三个整数n​​​​、m​​​​、k​​(2≤n≤5,2≤m≤5,2≤k≤n∗m​​​​),分别表示迷宫的行数、列数、移动的步数;接下来n​行,每行m​个整数(值为01),表示迷宫。

输出描述

   如果可行,那么输出Yes,否则输出No

输入

3 3 4

0 1 0

0 0 0

0 1 0

输出

Yes

#include <cstdio>

const int MAXN = 5;
int n, m, k, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
bool canReach = false;

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};

bool isValid(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !visited[x][y];
}

void DFS(int x, int y, int step) {
    if (canReach) { //这一步可以不写
        return;
    }
    if (x == n - 1 && y == m - 1) {
        if (step == k) {
            canReach = true; //通过设置canReach来记录是否为规定步数
        }
        return;
    }
    visited[x][y] = true;
    for (int i = 0; i < MAXD; i++) {
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (step < k && isValid(nextX, nextY)) {
            DFS(nextX, nextY, step + 1);
        }
    }
    visited[x][y] = false;
}

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    DFS(0, 0, 0);
    printf(canReach ? "Yes" : "No");
    return 0;
}

 ③矩阵最大权值问题

  题目描述

现有一个n∗m大小的矩阵,矩阵中的每个元素表示该位置的权值。现需要从矩阵左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置)。求最后到达右下角时路径上所有位置的权值之和的最大值。

 输入描述

    第一行两个整数n​​​、m​​​(2≤n≤5,2≤m≤5​​​),分别表示矩阵的行数和列数;

接下来n​​​行,每行m​​​个整数(−100≤​​整数≤100​​​),表示矩阵每个位置的权值。

输出描述

 一个整数,表示权值之和的最大值。

输入

2 2

1 2

3 4

输出

8

#include <cstdio>

const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};

bool isValid(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && !visited[x][y];
}

void DFS(int x, int y, int nowValue) {
    if (x == n - 1 && y == m - 1) {    
        if (nowValue > maxValue) {    //需要什么判定值,就在此处设置条件
            maxValue = nowValue;
        }
        return;
    }
    visited[x][y] = true;
    for (int i = 0; i < MAXD; i++) {
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (isValid(nextX, nextY)) {
            int nextValue = nowValue + maze[nextX][nextY];
            DFS(nextX, nextY, nextValue);
        }
    }
    visited[x][y] = false;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    DFS(0, 0, maze[0][0]);     //初始值为第一个位置的值
    printf("%d", maxValue);
    return 0;
}

 ④矩阵最大权值的路径

  题目描述

现有一个n∗m大小的矩阵,矩阵中的每个元素表示该位置的权值。现需要从矩阵左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置)。假设左上角坐标是(1,1),行数增加的方向为x增长的方向,列数增加的方向为y​增长的方向。求最后到达右下角时路径上所有位置的权值之和最大的路径。

 输入描述

第一行两个整数n​​​、m​​​(2≤n≤5,2≤m≤5​​​),分别表示矩阵的行数和列数;

接下来n​​​行,每行m​​​个整数(−100≤​​整数≤100​​​),表示矩阵每个位置的权值。

输出描述

从左上角的坐标开始,输出若干行(每行两个整数,表示一个坐标),直到右下角的坐标。

数据保证权值之和最大的路径存在且唯一。

输入

2 2

1 2

3 4

输出

1 1 

2 1

2 2

#include <cstdio>
#include <vector>
#include <utility>
using namespace std;

typedef pair<int, int> Position;  //使用pair将某位置的x,y值合为一体,不需要使用struct

const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;
vector<Position> tempPath, optPath;  //分为临时位置和最后位置,vector可理解为可变长数组

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};

bool isValid(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && !visited[x][y];
}

void DFS(int x, int y, int nowValue) {
    if (x == n - 1 && y == m - 1) {
        if (nowValue > maxValue) {
            maxValue = nowValue;
            optPath = tempPath;
        }
        return;
    }
    visited[x][y] = true;
    for (int i = 0; i < MAXD; i++) {
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (isValid(nextX, nextY)) {
            int nextValue = nowValue + maze[nextX][nextY];
            tempPath.push_back(Position(nextX, nextY));  //该点存入临时位置
            DFS(nextX, nextY, nextValue);          //临时位置被迭代到新的DFS里
            tempPath.pop_back();                   //将临时位置清空为0,方便存储新位置
        }
    }
    visited[x][y] = false;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    tempPath.push_back(Position(0, 0));
    DFS(0, 0, maze[0][0]);
    for (int i = 0; i < optPath.size(); i++) {
        printf("%d %d\n", optPath[i].first + 1, optPath[i].second + 1);//.first为pair使用方法
    }
    return 0;
}

 ⑤迷宫最大权值(此类问题经常出现,迷宫夺宝什么的)

  题目描述

现有一个n∗m​大小的迷宫,其中1表示不可通过的墙壁,0表示平地。现需要从迷宫左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。假设迷宫中每个位置都有权值,求最后到达右下角时路径上所有位置的权值之和的最大值。

 输入描述

第一行两个整数n​​​、m​​​(2≤n≤5,2≤m≤5​​​),分别表示矩阵的行数和列数;

接下来n行,每行m个整数(值为01),表示迷宫。

再接下来n​​​行,每行m​​​个整数(−100≤​​整数≤100​​​),表示迷宫每个位置的权值。

输出描述

一个整数,表示权值之和的最大值。

输入

3 3 

0 0 0

0 1 0

0 0 0

1 2 3

4 5 6

7 8 9

输出

29

 从左上角到右下角的最大权值之和为1+4+7+8+9=29​。

#include <cstdio>

const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN], isWall[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};

bool isValid(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && !isWall[x][y] && !visited[x][y];
}

void DFS(int x, int y, int nowValue) {
    if (x == n - 1 && y == m - 1) {
        if (nowValue > maxValue) {
            maxValue = nowValue;
        }
        return;
    }
    visited[x][y] = true;
    for (int i = 0; i < MAXD; i++) {
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (isValid(nextX, nextY)) {
            int nextValue = nowValue + maze[nextX][nextY];
            DFS(nextX, nextY, nextValue);
        }
    }
    visited[x][y] = false;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &isWall[i][j]);
        }
    }
    for (int i = 0; i < n; i++) {      //和上面题一样,顶多带一个值
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    DFS(0, 0, maze[0][0]);
    printf("%d", maxValue);
    return 0;
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玛卡巴卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值