M3558.给边赋权值的方案数 I
bfs, math, https://leetcode.cn/problems/number-of-ways-to-assign-edge-weights-i/description/
给你一棵 n 个节点的无向树,节点从 1 到 n 编号,树以节点 1 为根。树由一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示在节点 ui 和 vi 之间有一条边。
一开始,所有边的权重为 0。你可以将每条边的权重设为 1 或 2。
两个节点 u 和 v 之间路径的 代价 是连接它们路径上所有边的权重之和。
选择任意一个 深度最大 的节点 x。返回从节点 1 到 x 的路径中,边权重之和为 奇数 的赋值方式数量。
由于答案可能很大,返回它对 10^9 + 7 取模的结果。
注意: 忽略从节点 1 到节点 x 的路径外的所有边。
示例 1:

输入: edges = [[1,2]]
输出: 1
解释:
- 从节点 1 到节点 2 的路径有一条边(
1 → 2)。 - 将该边赋权为 1 会使代价为奇数,赋权为 2 则为偶数。因此,合法的赋值方式有 1 种。
示例 2:

输入: edges = [[1,2],[1,3],[3,4],[3,5]]
输出: 2
解释:
- 最大深度为 2,节点 4 和节点 5 都在该深度,可以选择任意一个。
- 例如,从节点 1 到节点 4 的路径包括两条边(
1 → 3和3 → 4)。 - 将两条边赋权为 (1,2) 或 (2,1) 会使代价为奇数,因此合法赋值方式有 2 种。
提示:
2 <= n <= 10^5edges.length == n - 1edges[i] == [ui, vi]1 <= ui, vi <= nedges表示一棵合法的树。
这道题结合了图论(树的遍历)与组合数学(二项式定理)。以下是对本题的详细解读、数学原理分析以及算法实现。
一、 题目核心解读
结合题目的定义与限制,可以将问题简化为以下几个步骤:
确定目标路径的长度:
- 题目要求选择任意一个最大深度的节点
。 - 深度定义为从根节点 1 到该节点的路径所包含的边数。
- 设树的最大深度为
。由于“忽略路径外的所有边”,实际上只需要关注这条长度为 的路径,路径上有且仅有 条边。
- 题目要求选择任意一个最大深度的节点
边权赋值的奇偶性约束:
- 每条边可以赋值为
1或2。 - 路径的代价为所有边权之和。要使这个和为奇数。
- 每条边可以赋值为
二、 数学原理推导
设路径上共有 1,剩下的 2。
此时,路径的总权重之和为:
要使 1 的边数)必须为奇数。
这意味着,需要在 1,其余位置赋值为 2。根据组合数,总方案数
根据二项式定理的性质,在一个大小为
因此,只要求出树的最大深度
三、 算法设计与实现
整个算法可以分为两步:
- 求最大深度:使用广度优先搜索(BFS)或深度优先搜索(DFS)遍历整棵树,求出从根节点 1 出发所能到达的最大深度
。 - 计算结果:使用快速幂求出
。
Python3 代码实现
from collections import deque
from typing import List
class Solution:
def assignEdgeWeights(self, edges: List[List[int]]) -> int:
n = len(edges) + 1
# 1. 构建邻接表
adj = [[] for _ in range(n + 1)]
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
# 2. BFS 寻找从节点 1 出发的最深距离 (最大深度)
max_depth = 0
queue = deque([(1, 0)]) # 存储队列元素: (当前节点, 深度)
visited = [False] * (n + 1)
visited[1] = True
while queue:
u, depth = queue.popleft()
if depth > max_depth:
max_depth = depth
for v in adj[u]:
if not visited[v]:
visited[v] = True
queue.append((v, depth + 1))
# 3. 计算结果
MOD = 10**9 + 7
return pow(2, max_depth - 1, MOD)四、 复杂度分析
时间复杂度:
- 建图需要遍历所有的边,耗时
。 - BFS 遍历中,每个节点和每条边最多被访问常数次,耗时
。 - 快速幂计算
的时间复杂度为 。 - 整体时间复杂度为
,在 的数据规模下可以快速运行完毕。
- 建图需要遍历所有的边,耗时
空间复杂度:
- 邻接表需要
的空间。 - 队列和
visited数组需要的空间。 - 整体辅助空间复杂度为
。
- 邻接表需要