深度优先搜索(DFS)的几个问题

总的来说,这些题都是第一道题的变形题 

1.迷宫可行路径数

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>

const int MAXN = 5;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = { false };//标记迷宫中的每个位置是否已经访问过,默认为 false
int counter = 0;

const int MAXD = 4;//定义了方向的数量,这里是四个方向:上、下、左、右。

//简化在二维空间中的方向移动操作
//分别定义了在 x 和 y 方向上的移动增量,用来方便地遍历四个方向。
int dx[MAXD] = { 0, 0, 1, -1 };

//dx[0] = 0:表示在 x 方向上不移动(保持当前列)
//dx[2] = 1:表示在 x 方向上向右移动一个单位
//dx[3] =-1:表示在 x 方向上向左移动一个单位。
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) {//如果当前位置 (x, y) 到达了迷宫的右下角 (n-1, m-1),
        counter++;
        //则将 counter 计数器加一,表示找到了一条从起点到终点的路径
        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)) {//如果isValid判断无效则再次进入for循环换一个方向遍历
            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);
    printf("%d", counter);
    return 0;
}

2.指定步数的迷宫问题

对DFS函数判断稍作修改

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>

const int MAXN = 5;
int n, m, k, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = { false };//标记迷宫中的每个位置是否已经访问过,默认为 false
bool canReach = false;
const int MAXD = 4;//定义了方向的数量,这里是四个方向:上、下、左、右。

//简化在二维空间中的方向移动操作
//分别定义了在 x 和 y 方向上的移动增量,用来方便地遍历四个方向。
int dx[MAXD] = { 0, 0, 1, -1 };

//dx[0] = 0:表示在 x 方向上不移动(保持当前列)
//dx[2] = 1:表示在 x 方向上向右移动一个单位
//dx[3] =-1:表示在 x 方向上向左移动一个单位。
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) {//如果当前位置 (x, y) 到达了迷宫的右下角 (n-1, m-1),
        if (step == k) {
            canReach = true;
        }
        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)) {//如果isValid判断无效则再次进入for循环换一个方向遍历
            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;
}

3.矩阵的最大值

结合1.迷宫可行路径数,代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>

const int MAXN = 5;
const int INF = 0x3f3f3f3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = { false };//标记迷宫中的每个位置是否已经访问过,默认为 false
int maxValue = -INF;

const int MAXD = 4;//定义了方向的数量,这里是四个方向:上、下、左、右。
//简化在二维空间中的方向移动操作
//分别定义了在 x 和 y 方向上的移动增量,用来方便地遍历四个方向。
int dx[MAXD] = { 0, 0, 1, -1 };
//dx[0] = 0:表示在 x 方向上不移动(保持当前列)
//dx[2] = 1:表示在 x 方向上向右移动一个单位
//dx[3] =-1:表示在 x 方向上向左移动一个单位。
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) {//如果当前位置 (x, y) 到达了迷宫的右下角 (n-1, 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)) {//如果isValid判断无效则再次进入for循环换一个方向遍历
            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;
}

注意以下代码:

const int INF = 0x3f3f3f3f;
... ...
int maxValue = -INF;

在这段代码中,定义 const int INF = 0x3f3f3f3f; 是为了表示一个无穷大的值,它实际上是十进制数 1061109567。这种表示方法通常用于算法中,特别是在动态规划或者搜索问题中,用来表示一个足够大的数值,作为无穷大的替代。

而为什么 int maxValue = -INF; 呢?这是因为在初始化时,我们希望 maxValue 初始值是一个负的无穷小,这样在搜索过程中能够确保任何有效的路径值都可以比较并更新 maxValue。因此,将 maxValue 初始化为 -INF 是为了确保它可以在后续的搜索中被正确更新为任何有效路径的最大值。

总结起来,INF-INF 的定义和使用是为了方便地处理路径搜索中的最大值问题,确保代码的逻辑和比较操作都能正确处理各种可能的路径值。

4.矩阵最大权值路径

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<vector>
#include<utility>

using namespace std;

typedef pair<int, int> Position;

const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = { false };//标记迷宫中的每个位置是否已经访问过,默认为 false
int maxValue = -INF;
vector<Position>tempPath, optPath;
//tempPath 用来暂时存储当前探索的路径,而 optPath 则记录找到的最优路径。

const int MAXD = 4;//定义了方向的数量,这里是四个方向:上、下、左、右。
//简化在二维空间中的方向移动操作
//分别定义了在 x 和 y 方向上的移动增量,用来方便地遍历四个方向。
int dx[MAXD] = { 0, 0, 1, -1 };
//dx[0] = 0:表示在 x 方向上不移动(保持当前列)
//dx[2] = 1:表示在 x 方向上向右移动一个单位
//dx[2] =-1:表示在 x 方向上向左移动一个单位。
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) {
//如果当前位置是迷宫的终点 (n-1, m-1),则更新最大价值路径 maxValue 和最优路径 optPath。
        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)) {//如果isValid判断无效则再次进入for循环换一个方向遍历
            int nextValue = nowValue + maze[nextX][nextY];
            
            tempPath.push_back(Position(nextX, nextY));
            //tempPath 用来暂时存储当前探索路径,每次递归调用前将下一个位置加入 tempPath,递归结束后再将其移除
            
            DFS(nextX, nextY, nextValue);
            tempPath.pop_back();
            //如果该路径走不通则弹出
        }
    }
    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);
        //最后输出最优路径 optPath 中的每个位置。
    }

    return 0;
}

这道题与 3.矩阵的最大值 不同的是要求输出路径坐标,坐标的输出可以考虑用STL中的pair,在递归过程中存储路径可以考虑用vector存储pair。

5.迷宫最大权值

这道题结合了1.迷宫可行路径数以及3.矩阵的最大值,即需要结合两个路径矩阵进行判断,修改结合了这两题的代码后,得到的代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
//#include<vector>
//#include<utility>

using namespace std;

//typedef pair<int, int> Position;

const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN],isWall[MAXN][MAXN];
bool visited[MAXN][MAXN] = { false };//标记迷宫中的每个位置是否已经访问过,默认为 false
int maxValue = -INF;
//vector<Position>tempPath, optPath;
//tempPath 用来暂时存储当前探索的路径,而 optPath 则记录找到的最优路径。

const int MAXD = 4;//定义了方向的数量,这里是四个方向:上、下、左、右。
//简化在二维空间中的方向移动操作
//分别定义了在 x 和 y 方向上的移动增量,用来方便地遍历四个方向。
int dx[MAXD] = { 0, 0, 1, -1 };
//dx[0] = 0:表示在 x 方向上不移动(保持当前列)
//dx[2] = 1:表示在 x 方向上向右移动一个单位
//dx[2] =-1:表示在 x 方向上向左移动一个单位。
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) {
//如果当前位置是迷宫的终点 (n-1, m-1),则更新最大价值路径 maxValue 和最优路径 optPath。
        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)) {//如果isValid判断无效则再次进入for循环换一个方向遍历
            int nextValue = nowValue + maze[nextX][nextY];
            
            //tempPath.push_back(Position(nextX, nextY));
            //tempPath 用来暂时存储当前探索路径,每次递归调用前将下一个位置加入 tempPath,递归结束后再将其移除
            
            DFS(nextX, nextY, nextValue);
            //tempPath.pop_back();
        }
    }
    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]);
        }
    }

    //tempPath.push_back(Position(0, 0));
    DFS(0, 0, maze[0][0]);
    printf("%d", maxValue);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值