HJ43 迷宫问题 ●●
描述
定义一个二维数组 N*M ,如 5 × 5 数组下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。
数据范围: 2 ≤ n , m ≤ 10 2≤n,m≤10 2≤n,m≤10 , 输入的内容只包含 0 ≤ v a l ≤ 1 0≤val≤1 0≤val≤1
输入描述:
输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
输出描述:
左上角到右下角的最短路径,格式如样例所示。
示例
输入:
5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
–
输出:
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)
题解
1. 回溯法
本题看似求最短路径,其实题目只有一条路径可走,因此采用回溯法进行深度优先搜索。
把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。
深度优先搜索的思想是沿着一个方向搜到底,如果行不通,则返回来试其他的路径。就一直这样直到找到一条通路输出就可以了。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool getPath(int currn, int currm, vector<vector<int>>& maze, vector<string>& ans){
int n = maze.size();
int m = maze[0].size();
maze[currn][currm] = 1; // 该点加入路径,并标记
string pos = "(" + to_string(currn) + "," + to_string(currm) + ")";
ans.emplace_back(pos);
if(currn == n-1 && currm == m-1) return true; // 到达终点
if(currn-1 >= 0 && maze[currn-1][currm] == 0){ // up
if(getPath(currn-1, currm, maze, ans)) return true;
}
if(currn+1 <= n-1 && maze[currn+1][currm] == 0){ // down
if(getPath(currn+1, currm, maze, ans)) return true;
}
if(currm-1 >= 0 && maze[currn][currm-1] == 0){ // left
if(getPath(currn, currm-1, maze, ans)) return true;
}
if(currm+1 <= m-1 && maze[currn][currm+1] == 0){ // right
if(getPath(currn, currm+1, maze, ans)) return true;
}
ans.pop_back(); // 走不通,回溯,恢复现场
maze[currn][currm] = 0;
return false;
}
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> maze(n, vector<int>(m, 0));
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
cin >> maze[i][j];
}
}
vector<string> ans;
getPath(0, 0, maze, ans);
for(auto str: ans){
cout << str << endl;
}
return 0;
}
如果题目中不止一条路径,则需要建立一个数组存储最短路径,同时递归回溯函数不使用返回值,而是遍历所有可能的路径,当找到新路径到达终点时则与最优路径进行比较。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void getMinPath(int currn, int currm, vector<vector<int>>& maze, vector<string>& currPath, vector<string>& minPath){
int n = maze.size();
int m = maze[0].size();
maze[currn][currm] = 1; // 该点加入路径,并标记
string pos = "(" + to_string(currn) + "," + to_string(currm) + ")";
currPath.emplace_back(pos);
if(currn == n-1 && currm == m-1){ // 到达终点,比较最优
if(minPath.empty()){
minPath = currPath;
}else if(currPath.size() < minPath.size()){
minPath = currPath;
}
}
if(currn-1 >= 0 && maze[currn-1][currm] == 0){ // up
getMinPath(currn-1, currm, maze, currPath, minPath);
}
if(currn+1 <= n-1 && maze[currn+1][currm] == 0){ // down
getMinPath(currn+1, currm, maze, currPath, minPath);
}
if(currm-1 >= 0 && maze[currn][currm-1] == 0){ // left
getMinPath(currn, currm-1, maze, currPath, minPath);
}
if(currm+1 <= m-1 && maze[currn][currm+1] == 0){ // right
getMinPath(currn, currm+1, maze, currPath, minPath);
}
currPath.pop_back(); // 走不通,回溯,恢复现场
maze[currn][currm] = 0;
}
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> maze(n, vector<int>(m, 0));
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
cin >> maze[i][j];
}
}
vector<string> currPath, minPath;
getMinPath(0, 0, maze, currPath, minPath);
for(auto str: minPath){
cout << str << endl;
}
return 0;
}