这是啥意思了?
vector<vector > maze = {
{0,0,1,0},
{0,0,0,0},
{0,0,1,0},
{0,1,0,0},
{0,0,0,1}
};
给一个maze迷宫,求里面的最短路径。其实这个和我上一篇中的全排列问题以及皇后问题还是比较像的。我们需要首先需要,判断某个位置是否被访问了,需要用到vectorused (二维的),表示是否被使用过。剪枝条件,数组是否越界,是不是可走。
下面写两种方法
第一种方法:
首先将开始节点在used中位置设置为1,后面的话判断下一个节点是否数组越界,是否有地图的阻碍。或者已经被访问。
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
//首先输出有多少可能
private:
void dfs(vector<vector<int>> &maze, vector<vector<bool>> &used, int current_i, int current_j, int target_i, int target_j, int &step, int &minstep, vector<vector<int>> &dxy)
{
if (current_i == target_i && current_j == target_j)
{
minstep = min(step, minstep);
return;
}
for (int i = 0;i < dxy.size();i++)
{
int temp_i = current_i + dxy[i][0];
int temp_j = current_j + dxy[i][1];
//if (used[temp_i][temp_j] == true)//这个是1判断是否被使用过(与上一篇递归文章中保持先判断是否使用,后面再判断剪枝) 但是这样会溢出,所以放在剪枝里面了
//{
// continue;
//}
if (temp_i < 0 || temp_i >= maze.size() || temp_j < 0 || temp_j >= maze[0].size() || maze[temp_i][temp_j] == 1 || used[temp_i][temp_j] == true)//这个相当于剪枝 (这种写法保证迷宫不是矩形也可以进行遍历)
{
continue;
}
step++;
used[temp_i][temp_j] = true;
dfs(maze, used, temp_i, temp_j, target_i, target_j, step, minstep, dxy);// temp_i, temp_j 就是下一次节点的current_i, current_j。
used[temp_i][temp_j] = false;
step--;
}
}
public:
//maze是一个二维数据 0代表可走,1代表不可走
int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int end_i, int end_j)
{
vector<vector<int>> dxy{ {0,1},{1,0},{0,-1},{-1,0} };//只有四种不同的方向 要是有多个情况加入进去,即可。
//下面这一行是保证当迷宫不是N行N列时候
vector<vector<bool> > used(maze.size(), vector<bool>(maze[0].size(), false));
//刚开始都没有使用过
//vector<vector<bool> > used(maze.size(), vector<bool>(maze.size(), false));
used[start_i][start_j] = true;
int minstep = INT_MAX;//刚开始设置为最大,后面只要找到了,路径(step)就比较,看哪个小一些即可
int step = 0;//
dfs(maze, used, start_i, start_j, end_i, end_j, step, minstep, dxy);
return minstep;
}
};
int main()
{
vector<vector<int> > maze = { {0,0,1,0},{0,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1} };
//vector<vector<int> > maze = { {0,0,0,0},{0,1,1,0},{0,1,1,0},{1,0,0,0} };
Solution s;
cout << s.getShortpath(maze, 0, 0, 3, 2);
//cout << s.getShortpath(maze, 0, 0, 3, 0);
}
第二种方法:
相当于之前那种便利的直接dfs(0)==>dfs(1),也就是说,将开始节点放入dfs(0) 中,每次判断当前节点是不是数组越界,或者当前位置是不是有阻碍,是不是,或者是不是已访问。
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
//首先输出有多少可能
private:
void dfs(vector<vector<int>> &maze, vector<vector<bool>> &used, int current_i, int current_j, int target_i, int target_j, int &step, int &minstep, vector<vector<int>> &dxy)
{
if (current_i == target_i && current_j == target_j)
{
minstep = min(step, minstep);
return;
}
for (int i = 0;i < dxy.size();i++)
{
//下面这种是完全模仿dfs(1),dfs(1)的这种形式
if (current_i < 0 || current_i >= maze.size() || current_j < 0 || current_j >= maze[0].size() || maze[current_i][current_j] == 1 || used[current_i][current_j] == true)//这个相当于剪枝 (这种写法保证迷宫不是矩形也可以进行遍历)
{
continue;
}
step++;
used[current_i][current_j] = true;
dfs(maze, used, current_i + dxy[i][0], current_j + dxy[i][1], target_i, target_j, step, minstep, dxy);// temp_i, temp_j 就是下一次节点的current_i, current_j。
used[current_i][current_j] = false;
step--;
}
}
public:
//maze是一个二维数据 0代表可走,1代表不可走
int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int end_i, int end_j)
{
vector<vector<int>> dxy{ {0,1},{1,0},{0,-1},{-1,0} };//只有四种不同的方向 要是有多个情况加入进去,即可。
//下面这一行是保证当迷宫不是N行N列时候
vector<vector<bool> > used(maze.size(), vector<bool>(maze[0].size(), false));
//刚开始都没有使用过
//vector<vector<bool> > used(maze.size(), vector<bool>(maze.size(), false));
//used[start_i][start_j] = true;
int minstep = INT_MAX;//刚开始设置为最大,后面只要找到了,路径(step)就比较,看哪个小一些即可
int step = 0;//
dfs(maze, used, start_i, start_j, end_i, end_j, step, minstep, dxy);
return minstep;
}
};
int main()
{
vector<vector<int> > maze = { {0,0,1,0},{0,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1} };
//vector<vector<int> > maze = { {0,0,0,0},{0,1,1,0},{0,1,1,0},{1,0,0,0} };
Solution s;
cout << s.getShortpath(maze, 0, 0, 3, 2);
//cout << s.getShortpath(maze, 0, 0, 3, 0);
}
当然还有中是输入是否有路劲,这种存在问题,我们可以直接在方法一上面改
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
//首先输出有多少可能
private:
void dfs(vector<vector<int>> &maze, vector<vector<bool>> &used, int current_i, int current_j, int target_i, int target_j, int &step, int &minstep, vector<vector<int>> &dxy,bool &tag)
{
if (current_i == target_i && current_j == target_j)
{
minstep = min(step, minstep);
tag =true;
return;
}
for (int i = 0;i < dxy.size();i++)
{
int temp_i = current_i + dxy[i][0];
int temp_j = current_j + dxy[i][1];
//if (used[temp_i][temp_j] == true)//这个是1判断是否被使用过(与上一篇递归文章中保持先判断是否使用,后面再判断剪枝) 但是这样会溢出,所以放在剪枝里面了
//{
// continue;
//}
if (temp_i < 0 || temp_i >= maze.size() || temp_j < 0 || temp_j >= maze[0].size() || maze[temp_i][temp_j] == 1 || used[temp_i][temp_j] == true)//这个相当于剪枝 (这种写法保证迷宫不是矩形也可以进行遍历)
{
continue;
}
step++;
used[temp_i][temp_j] = true;
if (tag == true) continue;
dfs(maze, used, temp_i, temp_j, target_i, target_j, step, minstep, dxy, tag);// temp_i, temp_j 就是下一次节点的current_i, current_j。
used[temp_i][temp_j] = false;
step--;
}
}
public:
//maze是一个二维数据 0代表可走,1代表不可走
int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int end_i, int end_j)
{
vector<vector<int>> dxy{ {0,1},{1,0},{0,-1},{-1,0} };//只有四种不同的方向 要是有多个情况加入进去,即可。
//下面这一行是保证当迷宫不是N行N列时候
vector<vector<bool> > used(maze.size(), vector<bool>(maze[0].size(), false));
//刚开始都没有使用过
//vector<vector<bool> > used(maze.size(), vector<bool>(maze.size(), false));
used[start_i][start_j] = true;
int minstep = INT_MAX;//刚开始设置为最大,后面只要找到了,路径(step)就比较,看哪个小一些即可
int step = 0;//
bool tag = false;
dfs(maze, used, start_i, start_j, end_i, end_j, step, minstep, dxy,tag);
if (tag == true) cout << "迷宫有解" << endl;
else cout << "迷宫无解" << endl;
return minstep;
}
};
int main()
{
vector<vector<int> > maze = { {0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0} };
Solution s;
cout << s.getShortpath(maze, 0, 0, 3, 0);//可以发现这是已经不是最短的,因为我们直招存在性,是符合题目要求的
}
其实这些算法就是在二叉树中求某一个点到根结点的距离,进行改的,因此我们需要注意基础。