本文涉及知识点
C++BFS算法动态规划汇总图论知识汇总 树形dp 换根法 BFS
LeetCode 2581. 统计可能的树根数目
Alice 有一棵 n 个节点的树,节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ai, bi] ,表示树中节点 ai 和 bi 之间有一条边。
Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这棵树进行若干次 猜测 。每一次猜测,Bob 做如下事情:
选择两个 不相等 的整数 u 和 v ,且树中必须存在边 [u, v] 。
Bob 猜测树中 u 是 v 的 父节点 。
Bob 的猜测用二维整数数组 guesses 表示,其中 guesses[j] = [uj, vj] 表示 Bob 猜 uj 是 vj 的父节点。
Alice 非常懒,她不想逐个回答 Bob 的猜测,只告诉 Bob 这些猜测里面 至少 有 k 个猜测的结果为 true 。
给你二维整数数组 edges ,Bob 的所有猜测和整数 k ,请你返回可能成为树根的 节点数目 。如果没有这样的树,则返回 0。
示例 1:
输入:edges = [[0,1],[1,2],[1,3],[4,2]], guesses = [[1,3],[0,1],[1,0],[2,4]], k = 3
输出:3
解释:
根为节点 0 ,正确的猜测为 [1,3], [0,1], [2,4]
根为节点 1 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 2 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 3 ,正确的猜测为 [1,0], [2,4]
根为节点 4 ,正确的猜测为 [1,3], [1,0]
节点 0 ,1 或 2 为根时,可以得到 3 个正确的猜测。
示例 2:
输入:edges = [[0,1],[1,2],[2,3],[3,4]], guesses = [[1,0],[3,4],[2,1],[3,2]], k = 1
输出:5
解释:
根为节点 0 ,正确的猜测为 [3,4]
根为节点 1 ,正确的猜测为 [1,0], [3,4]
根为节点 2 ,正确的猜测为 [1,0], [2,1], [3,4]
根为节点 3 ,正确的猜测为 [1,0], [2,1], [3,2], [3,4]
根为节点 4 ,正确的猜测为 [1,0], [2,1], [3,2]
任何节点为根,都至少有 1 个正确的猜测。
提示:
edges.length == n - 1
2 <= n <= 105
1 <= guesses.length <= 105
0 <= ai, bi, uj, vj <= n - 1
ai != bi
uj != vj
edges 表示一棵有效的树。
guesses[j] 是树中的一条边。
guesses 是唯一的。
0 <= k <= guesses.length
换根法
某棵有根树,根为root,某个儿子为child,则将根从root换成child后,除这条的边的父子关系发生变化外,其它都不边。
mGuesss[x] 记录猜测次数:x=Mask(r,v) = u*n+v
x1 = Mask(root,child)
x2 = Mask(child,root)
则 dp[child] = dp[root] - mGuesss[x1] + mGuress[x2]
分三步:
一,令root为0,计算m_dp[0]。
二,dfs各节点计算m_dp[cur]。
三,统计m_dp中为k的元素数量。
动态规划的状态表示
m_dp[cur]表示以cur为根据猜对父子关系的数量。
空间复杂度: O(n)
动态规划的转移方程
dp[child] = dp[root] - mGuesss[x1] + mGuress[x2]
单个状态的转移方程时间复杂度:O(1) 总时间复杂度:O(n)
动态规划的初始值
dp[0]先计算
动态规划的填表顺序
深度优先,广度优先也可以。
动态规划的返回值
cout(dp.being(),dp.end(),k)
代码(超时)
核心代码
单元测试
DFS非常容易超时
DFS稍稍复杂,leetcode就容易超时。
所以:
一,计算出临接表。
二,DFS各节点层次。
三,计算出各节点的孩子。
四,BFS各节点。由于每个节点顶多一个父亲,所以无需判断节点是否重复访问。
进一步优化
可以用数组代码映射,算法方向,总共2n-2条边。假定根为0的树。
如果这条边是 子节点执行父节点,则此边数是child。如果方向相反则是n + child。
运行速度大约提高了20%。
DFS序+差分数组
root和它的某个后代childchild换根。则到这条路径上的边都反转。可以用差分数组。
childchild和它的祖先不是连续的,但他们的DFS序是连续的。
此方案不好理解,实现也不简单。备用。
我想对大家说的话 |
《喜缺全书算法册》以原理、正确性证明、总结为主。 |
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。