本文涉及知识点

C++图论C++DFS

LeetCode1443. 收集树上所有苹果的最少时间

给你一棵有 n 个节点的无向树,节点编号为 0 到 n-1 ,它们中有一些节点有苹果。通过树上的一条边,需要花费 1 秒钟。你从 节点 0 出发,请你返回最少需要多少秒,可以收集到所有苹果,并回到节点 0 。

无向树的边由 edges 给出,其中 edges[i] = [fromi, toi] ,表示有一条边连接 from 和 toi 。除此以外,还有一个布尔数组 hasApple ,其中 hasApple[i] = true 代表节点 i 有一个苹果,否则,节点 i 没有苹果。

示例 1:

【C++ 图论 DFS】1443. 收集树上所有苹果的最少时间|1682_算法

输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,true,true,false]

输出:8

解释:上图展示了给定的树,其中红色节点表示有苹果。一个能收集到所有苹果的最优方案由绿色箭头表示。

示例 2:

【C++ 图论 DFS】1443. 收集树上所有苹果的最少时间|1682_算法_02

输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,false,true,false]
输出:6
解释:上图展示了给定的树,其中红色节点表示有苹果。一个能收集到所有苹果的最优方案由绿色箭头表示。
示例 3:

输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,false,false,false,false,false]
输出:0

提示:
1 <= n <= 105
edges.length == n - 1
edges[i].length == 2
0 <= ai < bi <= n - 1
hasApple.length == n

后序DFS

DFS(cur) 返回 是否有苹果,收集所有的苹果需要的时间。
由于是树(连通、无环图),故只有一个父节点,用父节点除重。
如果子树没有苹果无需访问。 否则总时间:2 + 子树需要的时间。

代码

核心代码

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>> 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 Solution {
		public:
			int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
				auto neiBo = CNeiBo::Two(n, edges, false, 0);
				function<pair<bool, int>(int, int)> DFS = [&](int cur, int par) {
					int time = 0;
					bool bHas = hasApple[cur];
					for (const auto& next : neiBo[cur]) {
						if (par == next) { continue; }
						auto [b, t] = DFS(next, cur);
						if (!b) { continue; }
						time += 2 + t;
						bHas = true;
					}
					return make_pair( bHas,time );
				};
				auto [tmp,ans] = DFS(0, -1);
				return ans;
			}			
		};

单元测试

int n;
		vector<vector<int>> edges;
		vector<bool> hasApple;
		TEST_METHOD(TestMethod11)
		{
			n = 7, edges = { {0,1},{0,2},{1,4},{1,5},{2,3},{2,6} }, hasApple = { false,false,true,false,true,true,false };
			auto res = Solution().minTime(n, edges, hasApple);
			AssertEx(8, res);
		}
		TEST_METHOD(TestMethod12)
		{
			n = 7, edges = { {0,1},{0,2},{1,4},{1,5},{2,3},{2,6} }, hasApple = { false,false,true,false,false,true,false };
			auto res = Solution().minTime(n, edges, hasApple);
			AssertEx(6, res);
		}
		TEST_METHOD(TestMethod13)
		{
			n = 7, edges = { {0,1},{0,2},{1,4},{1,5},{2,3},{2,6} }, hasApple = { false,false,false,false,false,false,false };
			auto res = Solution().minTime(n, edges, hasApple);
			AssertEx(0, res);
		}


测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

【C++ 图论 DFS】1443. 收集树上所有苹果的最少时间|1682_算法_03