DFS求解迷宫最长移动路线
来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题
本文给出了C++实现代码,介绍了 STL 中容器vector
,pair
,unordered_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 && // 检查列是否越界!visited[ni][nj] && // 检查是否已访问matrix