一、迷宫最短路径问题
给你一个m*n的迷宫,迷宫中有障碍物(1表示障碍物),你可以上下左右移动,但不能走走过的迷宫,给出指定的起点(x,y)和指定的终点(x_l,y_l),求最短路径长度是多少,或者打印其中一个最短路径,
输入:nums={
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
};
输出:最短路径长度:8
最段路径为: 1 0,2 0,3 0,4 0,4 1,4 2,4 3,4 4
思路:1.使用DFS深度优先遍历来到达终点的所有路径,选择最短的路径。
2.使用BFS层序遍历,一层一层往外扩张,使用结构体简化操作
DFS
//***************************上下左右迷宫,有障碍物,DFS************************
vector<int> dx = { -1,1,0,0 };
vector<int> dy = { 0,0,-1,1 };
vector<vector<int>> path;
vector<vector<int>> res;
void dfs(vector<vector<int>> nums,int x,int y,int x_l,int y_l) {
if (x == x_l && y == y_l) {
if (res.size() == 0 || res.size() > path.size()) res = path; //更新最短路径
return;
}
for (int i = 0; i < 4; i++) { //上下左右
int x_currt = x + dx[i];
int y_currt = y + dy[i];
if (x_currt < 0 || x_currt >= nums.size() || y_currt < 0 || y_currt>=nums[0].size() //边界条件,障碍物,已经走过
|| nums[x_currt][y_currt] == -1 || nums[x_currt][y_currt] == 1) continue;
nums[x_currt][y_currt] = -1;
path.push_back({ x_currt ,y_currt });
dfs(nums, x_currt, y_currt, x_l, y_l);
path.pop_back();
}
}
BFS(1.每个结构用path记录)
//***************************上下左右迷宫,有障碍物,BFS**********************
//使用队列辅助,每层出栈时,把下层的压栈。
class P {
public:
int x; //横坐标
int y; //纵坐标
int len; //路径长度
vector<vector<int>> path; //记录路径
};
void bfs(vector<vector<int>> nums, int x, int y, int x_l, int y_l) {
queue<P> que; //用队列记录每个结构体在每层的路径和路径长度,这样同一层的点的路径长度是相同的。
vector<vector<int>> path;
P currt;
currt.x = x;
currt.y = y;
currt.len = 0;
currt.path = path;
que.push(currt); //入队
while (!que.empty()) {
currt = que.front(); //弹出队首结点
que.pop();
if (currt.x == x_l && currt.y == y_l) { //如果这一层是终点则退出遍历
cout << "最短路径长度:"<<currt.len << endl; //输出最短路径长度
for (int i = 0; i < currt.path.size(); i++) //输出路径
cout << currt.path[i][0] << " " << currt.path[i][1] << endl;
return;
}
for (int i = 0; i < 4; i++) { //上下左右
int x_currt = currt.x + dx[i];
int y_currt = currt.y + dy[i];
if (x_currt < 0 || x_currt >= nums.size() || y_currt < 0 || y_currt >= nums[0].size() //判断边界条件和障碍以及走过
|| nums[x_currt][y_currt] == -1 || nums[x_currt][y_currt] == 1) continue;
P next;
next.x = x_currt;
next.y = y_currt;
next.len = currt.len + 1;
next.path = currt.path;
next.path.push_back({ x_currt ,y_currt});
que.push(next); //把下一层的点压入队列
nums[x_currt][y_currt] = -1; //标记走过的路
}
}
return ;
}
BFS(2.每个结构用father指针记录)
#include<bits/stdc++.h>
using namespace std;
vector<int> dx = { -1,1,0,0 };
vector<int> dy = { 0,0,-1,1 };
class P{
public:
int x;
int y;
P* father; //指针指向上一层的父亲结点
P(int x,int y):x(x),y(y),father(NULL){} //新建结点
};
P* bfs(vector<vector<int>>&nums){
queue<P*> que;
P* currt=new P(0,0);
currt->father=currt;
que.push(currt);
while(!que.empty()){
currt=que.front();
if(currt->x == nums.size()-1 && currt->y == nums[0].size()-1) return currt;
que.pop();
for(int i=0;i<4;i++){
int x_l=currt->x+dx[i];
int y_l=currt->y+dy[i];
if(x_l<0 || x_l>=nums.size() || y_l<0 || y_l>=nums[0].size() || nums[x_l][y_l]==1) continue;
P* next=new P(x_l,y_l);
next->father=currt;
que.push(next);
nums[x_l][y_l]=1;
}
}
return currt;
}
int main(){
int m,n;
cin>>m>>n;
vector<vector<int>> nums(m,vector<int>(n));
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
int c;
cin>>c;
nums[i][j]=c;
}
P* cur=bfs(nums);
vector<vector<int>> res;
res.push_back({cur->x,cur->y}); //遍历逆行寻找父亲结点,直到找到0,0坐标结点。
while(1){
cur=cur->father;
res.push_back({cur->x,cur->y});
if(cur->x ==0 && cur->y == 0) break;
}
for(int i=res.size()-1;i>=0;i--){ //逆向打印
cout<<'('<<res[i][0]<<','<<res[i][1]<<')'<<endl;
}
}
二、矩阵最长递增序列(记忆化搜索+dfs减少遍历时间)
class Solution {
public:
//一下代码适合于通用版本,针对本题可优化,取消path路径(只与上次比较),取消记录走过的结点(因为递增不可能走重复路)
int longestIncreasingPath(vector<vector<int>>& matrix) {
vector<vector<int>> moem(matrix.size(),vector<int>(matrix[0].size(),-1)); //记忆化数组
for(int i=0;i<matrix.size();i++)
for(int j=0;j<matrix[0].size();j++){
path.push_back(matrix[i][j]);
res=max(res,dfs(matrix,i,j,moem));
path.pop_back();
}
return res;
}
int d_x[6]={1,-1,0,0};
int d_y[6]={0,0,1,-1};
vector<int>path; //记录路径
int res=1;
int dfs(vector<vector<int>>& matrix,int x,int y,vector<vector<int>>& moem){
if(moem[x][y]!=-1) return moem[x][y]; //如果已经是之前遍历过的,并更新了该点开始的递增路径,就退出不再重复遍历了
int ans=0;
for(int i=0;i<=3;i++){
int newx=x+d_x[i];
int newy=y+d_y[i];
if(newx<0 || newx>=matrix.size() || newy<0 || newy>=matrix[0].size() || matrix[newx][newy]==-1 || matrix[newx][newy]<=path[path.size()-1]) continue;
int temp=matrix[newx][newy];
matrix[newx][newy]=-1;
path.push_back(temp);
int back=dfs(matrix,newx,newy,moem);
ans=max(ans,back); //返回周围能递增的最长路径长度
path.pop_back();
matrix[newx][newy]=temp;
}
moem[x][y]=ans+1; //更新记忆化数组,下次遍历到该点不用再遍历
return ans+1;
}
};