DFS求解迷宫最长移动路线

来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题
本文给出了C++实现代码,介绍了 STL 中容器vectorpairunordered_set 的应用,供信奥选手参考。迷宫类问题适合用DFS算法解决,本文最后总结了DFS算法的两种常见实现方式——递归实现、栈实现,应用场景——迷宫类问题、图的连通性、树的遍历、拓朴排序、排列组合,以及主要优缺点。

题目描述

有一个 N*M 的矩阵,且矩阵中的每个方格都有一个整数(0≤整数≤100),小蓝需要按照以下要求从矩阵中找出一条最长的移动路线,且输出最长路线的长度(1 个方格为 1 个长度)。

要求:
1.小蓝可以从矩阵中任意一个方格开始向它的上、下、左、右相邻的任意一个方格移动,且移动的路线不能有交叉;
2.小蓝每次所要移动到的方格中的整数都要小于当前所在方格中的整数(如当前所在的方格中的整数为 3,那么可以移动到数字为 0,1,2 的格子里,不可以移动到数字为 3,4,5…的格子里);

例如:
N=3,M=3,矩阵方格如下:
在这里插入图片描述
最长路线为 4 -> 3 -> 2 -> 1,故路线长度为 4。

输入描述:
第一行输入两个正整数 N,M(1<N≤1000,1<M≤1000),N 表示矩阵的行数,M 表示矩阵的列数,两个正整数之间以一个空格隔开
第二行开始输入 N 行,每行包含 M 个整数(0≤每个整数≤100),表示每个方格中的整数,每个整数之间以一个空格隔开

输出描述:
输出一个整数,表示最长路线的长度

样例输入:

3 3
1 1 3
2 3 4
1 1 1

样例输出:

4

参考答案

方法一

#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>

using namespace std;

struct PairHash {
   
    template <class T1, class T2>
    size_t operator()(const pair<T1, T2>& p) const {
   
        auto h1 = hash<T1>{
   }(p.first);
        auto h2 = hash<T2>{
   }(p.second);
        return h1 ^ (h2 << 1);
    }
};

int dfs(int i, int j, unordered_set<pair<int, int>, PairHash>& visited, 
        vector<vector<int>>& matrix, int rows, int cols) {
   
    // 1. 基本状态: 当前位置已经计入路径长度
    int current_length = 1;
    
    // 2. 定义四个移动方向: 上、下、左、右
    vector<pair<int, int>> directions = {
   {
   -1, 0}, {
   1, 0}, {
   0, -1}, {
   0, 1}};
    
    // 3. 遍历每个可能的移动方向
    for (const auto& dir : directions) {
   
        // 计算新位置的坐标
        int ni = i + dir.first;
        int nj = j + dir.second;
        
        // 4. 检查移动的合法性
        if (ni >= 0 && ni < rows &&     // 检查行是否越界
            nj >= 0 && nj < cols &&     // 检查列是否越界
            visited.find({
   ni, nj}) == visited.end() &&  // 检查是否已访问
            matrix[ni][nj] < matrix[i][j]) {
              // 检查数字是否更小
            
            // 5. 递归探索
            visited.insert({
   ni, nj});    // 标记已访问
            // 计算包含当前位置的最长路径
            current_length = max(current_length, 1 + dfs(ni, nj, visited, matrix, rows, cols));
            visited.erase({
   ni, nj});     // 回溯,移除访问标记
        }
    }
    
    return current_length;
}

int longestPath(vector<vector<int>>& matrix) {
   
    int rows = matrix.size();
    int cols = matrix[0].size();
    int max_length = 0;
    
    // 6. 遍历矩阵中的每个位置作为起点
    for (int i = 0; i < rows; i++) {
   
        for (int j = 0; j < cols; j++) {
   
            unordered_set<pair<int, int>, PairHash> visited;
            visited.insert({
   i, j});  // 初始位置标记为已访问
            int length = dfs(i, j, visited, matrix, rows, cols);
            max_length = max(max_length, length);
        }
    }
    
    return max_length;
}

int main() {
   
    int N, M;
    cin >> N >> M;
    
    // 读取输入矩阵
    vector<vector<int>> matrix(N, vector<int>(M));
    for (int i = 0; i < N; i++) {
   
        for (int j = 0; j < M; j++) {
   
            cin >> matrix[i][j];
        }
    }
    
    // 计算并输出结果
    int result = longestPath(matrix);
    cout << result << endl;
    
    return 0;
}

方法二

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int dfs(int i, int j, vector<vector<bool>>& visited, 
        vector<vector<int>>& matrix, int rows, int cols) {
   
    int current_length = 1;
    
    vector<pair<int, int>> directions = {
   {
   -1, 0}, {
   1, 0}, {
   0, -1}, {
   0, 1}};
    
    for (const auto& dir : directions) {
   
        int ni = i + dir.first;
        int nj = j + dir.second;
        
        if (ni >= 0 && ni < rows &&     // 检查行是否越界
            nj >= 0 && nj < cols 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值