【01BFS】2290. 到达角落需要移除障碍物的最小数目

本文涉及知识点

01BFS
C++BFS算法

图论知识汇总

LeetCode2290. 到达角落需要移除障碍物的最小数目

给你一个下标从 0 开始的二维整数数组 grid ,数组大小为 m x n 。每个单元格都是两个值之一:

0 表示一个 空 单元格,

1 表示一个可以移除的 障碍物 。

你可以向上、下、左、右移动,从一个空单元格移动到另一个空单元格。

现在你需要从左上角 (0, 0) 移动到右下角 (m - 1, n - 1) ,返回需要移除的障碍物的 最小 数目。

示例 1:

输入:grid = [[0,1,1],[1,1,0],[1,1,0]]

输出:2

解释:可以移除位于 (0, 1) 和 (0, 2) 的障碍物来创建从 (0, 0) 到 (2, 2) 的路径。

可以证明我们至少需要移除两个障碍物,所以返回 2 。

注意,可能存在其他方式来移除 2 个障碍物,创建出可行的路径。

示例 2:

输入:grid = [[0,1,0,0,0],[0,1,0,1,0],[0,0,0,1,0]]

输出:0

解释:不移除任何障碍物就能从 (0, 0) 到 (2, 4) ,所以返回 0 。

提示:

m == grid.length

n == grid[i].length

1 <= m, n <= 105

2 <= m * n <= 105

grid[i][j] 为 0 或 1

grid[0][0] == grid[m - 1][n - 1] == 0

01BFS

无障碍物权重为0,有障碍物权重为1。

代码

核心代码

cpp 复制代码
class CNeiBo
{
public:	
	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) 
	{
		vector<vector<int>>  vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);
			}
		}
		return vNeiBo;
	}	
	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0)
	{
		vector<vector<std::pair<int, int>>> vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Grid(int rCount, int cCount, std::function<bool(int, int)> funVilidCur, std::function<bool(int, int)> funVilidNext)
	{
		vector<vector<int>> vNeiBo(rCount * cCount);
		auto Move = [&](int preR, int preC, int r, int c)
		{
			if ((r < 0) || (r >= rCount))
			{
				return;
			}
			if ((c < 0) || (c >= cCount))

			{
				return;
			}
			if (funVilidCur(preR, preC) && funVilidNext(r, c))
			{
				vNeiBo[cCount * preR + preC].emplace_back(r * cCount + c);
			}
		};

		for (int r = 0; r < rCount; r++)
		{
			for (int c = 0; c < cCount; c++)
			{
				Move(r, c, r + 1, c);
				Move(r, c, r - 1, c);
				Move(r, c, r, c + 1);
				Move(r, c, r, c - 1);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Mat(vector<vector<int>>& neiBoMat)
	{
		vector<vector<int>> neiBo(neiBoMat.size());
		for (int i = 0; i < neiBoMat.size(); i++)
		{
			for (int j = i + 1; j < neiBoMat.size(); j++)
			{
				if (neiBoMat[i][j])
				{
					neiBo[i].emplace_back(j);
					neiBo[j].emplace_back(i);
				}
			}
		}
		return neiBo;
	}
};

class C01BFSDis
{
public:
	C01BFSDis(vector<vector<int>>& vNeiB0, vector<vector<int>>& vNeiB1, int s)
	{
		m_vDis.assign(vNeiB0.size(), -1);
		std::deque<std::pair<int, int>> que;
		que.emplace_back(s, 0);
		while (que.size())
		{
			auto it = que.front();
			const int cur = it.first;
			const int dis = it.second;
			que.pop_front();
			if (-1 != m_vDis[cur])
			{
				continue;
			}
			m_vDis[cur] = it.second;
			for (const auto next : vNeiB0[cur])
			{
				if (-1 != m_vDis[next])
				{
					continue;
				}
				que.emplace_front(next, dis);

			}

			for (const auto next : vNeiB1[cur])
			{
				if (-1 != m_vDis[next])
				{
					continue;
				}
				que.emplace_back(next, dis + 1);
			}
		}
	}
public:
	vector<int> m_vDis;
};

class Solution {
public:
	int minimumObstacles(vector<vector<int>>& grid) {
		const int R = grid.size();
		const int C = grid[0].size();		
		auto neiBo0 = CNeiBo::Grid(R, C, [](int r, int c) {return true; }, [&](int r, int c) {return 0 == grid[r][c]; });
		auto neiBo1 = CNeiBo::Grid(R, C, [](int r, int c) {return true; }, [&](int r, int c) {return 1 == grid[r][c]; });
		C01BFSDis bfs(neiBo0,neiBo1,0);
		return bfs.m_vDis.back();
	}
};

单元测试

cpp 复制代码
template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{
	Assert::AreEqual(t1, t2);
}

template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
	Assert::AreEqual(v1.size(), v2.size());
	for (int i = 0; i < v1.size(); i++)
	{
		Assert::AreEqual(v1[i], v2[i]);
	}
}

template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
	sort(vv1.begin(), vv1.end());
	sort(vv2.begin(), vv2.end());
	Assert::AreEqual(vv1.size(), vv2.size());
	for (int i = 0; i < vv1.size(); i++)
	{
		AssertEx(vv1[i], vv2[i]);
	}
}

namespace UnitTest
{
	vector<vector<int>> grid;
	TEST_CLASS(UnitTest)
	{
	public:
		TEST_METHOD(TestMethod00)
		{
			grid = { {0,1,1},{1,1,0},{1,1,0} };
			auto res = Solution().minimumObstacles(grid);
			AssertEx(2, res);
		}
		TEST_METHOD(TestMethod01)
		{
			grid = { {0,1,0,0,0},{0,1,0,1,0},{0,0,0,1,0} };
			auto res = Solution().minimumObstacles(grid);
			AssertEx(0, res);
		}
	};
}

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关推荐
‘’林花谢了春红‘’27 分钟前
C++ list (链表)容器
c++·链表·list
机器视觉知识推荐、就业指导2 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Swift社区3 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman3 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
IT 青年4 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Yang.994 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王4 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_4 小时前
C++自己写类 和 运算符重载函数
c++
Dong雨4 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展