最全迷宫最短路径问题(BFS、DFS)

一、迷宫最短路径问题

   给你一个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
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;
    }
}

最全迷宫最短路径问题(BFS、DFS)_第1张图片

二、矩阵最长递增序列(记忆化搜索+dfs减少遍历时间)

最全迷宫最短路径问题(BFS、DFS)_第2张图片


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;
    }
};

你可能感兴趣的:(深度优先,宽度优先,算法,leetcode,1024程序员节)