1293. 网格中的最短路径

题目:
1293. 网格中的最短路径链接
1294. 在这里插入图片描述
在这里插入图片描述

思路:
这题我们可以采用bfs和dfs来做,首先我们需要明白bfs由于相当于没有回溯的过程,因此bfs是不需要遍历完所有节点就可以找到到目的的最短路径,但是由于dfs有借助于回溯的思想,因此是需要遍历完所有节点才可以知道最短路径长度。

方法一bfs:思路
首先,我们采用seen这个二维的vector里面存放着从起始点以相同的步数走到当前位置过程中,这个位置存放的最小的障碍obstacle数目(由于后面做了剪枝,因此只要obstacle数目>k ,我们就认为当前存放的obstacle=INT_MAX),

我们知道借助队列进行bfs的第一步是放入一个位置到队列中,下列代码

qu.push({0,0,0});//start_i,start_j,obstacleNumbers

{0,0,0} 第一个,和第二个0代表起始位置 start_i,start_j,第三个代表其实的障碍数目,由于题目中有grid[0][0] == grid[m-1][n-1] == 0 可以知道最开始的起始位置是没有障碍物的,因此obstacleNumbers=0;

我认为这道题是关于消除障碍的bfs重要的第二步,和以往的bfs中的used中的不同(普通的迷宫问题可以根据used判断是否可以走)。
下列代码

 
    if(isArea(grid,temp_i,temp_j))
    {
        int newObstacle=current[2]+grid[temp_i][temp_j];
        int oldObstacle=seen[temp_i][temp_j];

        if(newObstacle<oldObstacle&&newObstacle<=k)
        {
            qu.push({temp_i,temp_j,newObstacle});
            seen[temp_i][temp_j]=newObstacle;
        }

    }

当我们发现newObstacle<seen[temp_i][temp_j] 我们需要更新seen ,因为还有比之前存的相同步数到达这个位置更小的障碍obstacle数目。(也就是到达此位置我们碰到的1的数目可以更少。)不然就是不可走(不用入队列)

方法二dfs:思路 leetcode会超时
dfs其实就是传入变量时有 k 这个k代表还剩多少次可以消除障碍的机会。因此这样的话在dfs我们需要注意

  1. 没有障碍时(grid[temp_i][temp_j] == 0)可以直接dfs,
  2. 有障碍时(grid[temp_i][temp_j] == 1){k–;然后dfs}
if (grid[temp_i][temp_j] == 0)
	{
                
		dfs(grid, used, temp_i, temp_j, k, step);
                 used[temp_i][temp_i] = false;
	}

	if (k > 0 && grid[temp_i][temp_j] == 1)
	{
                
		k--;

		dfs(grid, used, temp_i, temp_j, k, step);

		k++;
                
	}

代码:
方法一:bfs

class Solution {
private:
    vector<vector<int>> dxy{{0,-1},{-1,0},{0,1},{1,0}};
    bool isArea(vector<vector<int>>& grid,int temp_i,int temp_j)
    {
        if(temp_i<0||temp_i>=grid.size()||temp_j<0||temp_j>=grid[0].size())  return false;

        return true;
    }

public:
    int shortestPath(vector<vector<int>>& grid, int k)
    {
        //一般来说  bfs的路径会是最短路径  seen是存放着与迷宫大小同等维度的,里面的数代表着从开始到当前节点的最小阻碍数目
        vector<vector<int>> seen(grid.size(),vector<int>(grid[0].size(),INT_MAX));

        int step=0;
        queue<vector<int>> qu;
        qu.push({0,0,0});//start_i,start_j,obstacleNumbers

        while(!qu.empty())
        {
            int n=qu.size();
            for(int i=0;i<n;i++)
            {

                vector<int>  current=qu.front();
                qu.pop();

                if(current[0]==grid.size()-1&&current[1]==grid[0].size()-1)
                {
                    return step;
                }

                for(int j=0;j<dxy.size();j++)
                {   
                    int temp_i=current[0]+dxy[j][0];
                    int temp_j=current[1]+dxy[j][1];

                   
                    if(isArea(grid,temp_i,temp_j))
                    {
                        int newObstacle=current[2]+grid[temp_i][temp_j];
                        int oldObstacle=seen[temp_i][temp_j];
                        
                        if(newObstacle<oldObstacle&&newObstacle<=k)
                        {
                            qu.push({temp_i,temp_j,newObstacle});
                            seen[temp_i][temp_j]=newObstacle;
                        }
                    }
                }
            }
            step++;//随着每次队列向外面扩展一次,步数也会加一


        }
        return -1;

    }
};

方法二dfs:思路 leetcode会超时



class Solution {
private:
	int global_min = INT_MAX;
	vector<vector<int>> dxy{ {0,1},{1,0},{0,-1},{-1,0} };
	bool isArea(vector<vector<int>>& grid,int &temp_i,int &temp_j)
	{
		if (temp_i < 0 || temp_i >= grid.size() || temp_j < 0 || temp_j >= grid[0].size()) return false;

		return true;
		
	}

	void dfs(vector<vector<int>>&grid, vector<vector<bool>>&used, int current_i, int current_j, int &k,int &step)
	{
       // cout<<"current_i="<<current_i<<"current_j="<<current_j<<endl;

		if (current_i== grid.size()-1&&current_j==grid[0].size()-1)
		{
			global_min = min(global_min,step); 
           // cout<<"step="<<step<<endl;
			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 (isArea(grid, temp_i, temp_j) && used[temp_i][temp_j] == false)//&&grid[start_i][start_j]==0 
			{
				
                 used[temp_i][temp_j] = true;
                 step++;
				if (grid[temp_i][temp_j] == 0)
				{
                   
					dfs(grid, used, temp_i, temp_j, k, step);
                    used[temp_i][temp_i] = false;
				}

				if (k > 0 && grid[temp_i][temp_j] == 1)
				{
                   
					k--;

					dfs(grid, used, temp_i, temp_j, k, step);

					k++;
                   
				}
                 step--;
                 used[temp_i][temp_j] = false;

				
				
			}

		}

	}
public:
	int shortestPath(vector<vector<int>>& grid, int k)
	{
       // cout<<"raw="<<grid.size()<<"col="<<grid[0].size()<<endl;
		vector<vector<bool>> used (grid.size(), vector<bool>(grid[0].size(), false));
		int start_i = 0;
		int start_j = 0;
		int step = 0;
	

		used[start_i][start_j] == true;
		

        dfs(grid, used, start_i, start_j, k, step);

		return global_min==INT_MAX?-1:global_min;

		
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值