2025-11-09:给边赋权值的方案数Ⅰ。用go语言,给定一棵以节点 1 为根的无向树,共 n 个节点,边由长度为 n−1 的

举报
福大大架构师每日一题 发表于 2025/11/09 07:09:13 2025/11/09
【摘要】 2025-11-09:给边赋权值的方案数Ⅰ。用go语言,给定一棵以节点 1 为根的无向树,共 n 个节点,边由长度为 n−1 的数组 edges 给出(每个元素 [u,v] 表示 u 与 v 之间有一条边)。起初所有边的权重为 0,但你可以把每条边设为权值 1 或 2。任选一个与根节点 1 距离最大的节点 x(即最远的节点)。只看从节点 1 到该节点 x 的那条简单路径(路径之外的边不参与计...

2025-11-09:给边赋权值的方案数Ⅰ。用go语言,给定一棵以节点 1 为根的无向树,共 n 个节点,边由长度为 n−1 的数组 edges 给出(每个元素 [u,v] 表示 u 与 v 之间有一条边)。起初所有边的权重为 0,但你可以把每条边设为权值 1 或 2。

任选一个与根节点 1 距离最大的节点 x(即最远的节点)。只看从节点 1 到该节点 x 的那条简单路径(路径之外的边不参与计数),统计有多少种将该路径上每条边的权值设为 1 或 2 的方法,使得从 1 到 x 的边权总和为奇数。

结果要求对 1000000007 取模后输出。

2 <= n <= 100000。

edges.length == n - 1。

edges[i] == [ui, vi]。

1 <= ui, vi <= n。

edges 表示一棵合法的树。

在这里插入图片描述

输入: edges = [[1,2],[1,3],[3,4],[3,5]]。

输出: 2。

解释:

最大深度为 2,节点 4 和节点 5 都在该深度,可以选择任意一个。

例如,从节点 1 到节点 4 的路径包括两条边(1 → 3 和 3 → 4)。

将两条边赋权为 (1,2) 或 (2,1) 会使代价为奇数,因此合法赋值方式有 2 种。

题目来自力扣3558。

问题分析过程

这个问题要求计算在树结构中,从根节点到最深叶子节点的路径上,通过给边赋权值1或2,使得路径总权值为奇数的方案数。以下是详细的分步分析:

1. 构建树结构

首先需要根据输入的边数组构建树的邻接表表示。由于树是无向的,每条边需要在两个节点的邻接表中都添加对方节点,从而形成完整的连通图结构。

2. 计算最大深度

通过深度优先搜索(DFS)从根节点(节点1)开始遍历整棵树,计算每个节点的深度(到根节点的距离)。在DFS过程中,维护当前深度信息,递归访问每个未访问过的子节点(避免回溯到父节点),最终得到整棵树的最大深度k。

3. 确定路径边数

从根节点到最深节点x的路径边数等于最大深度k(因为深度是从根节点开始计算的节点层数,边数比深度少1)。因此实际需要赋权的边数为n = k-1

4. 分析权值赋值方案

路径总权值为奇数的条件等价于路径上权值为1的边必须有奇数条(因为每条边权值只能是1或2,而2不会改变总和的奇偶性)。问题转化为:在n条边中选择奇数条边赋权为1,其余赋权为2。

5. 计算方案数

组合数学结论:从n条边中选择奇数条边的方案总数为2^(n-1)。这可以通过二项式定理证明:选择奇数个元素的方案数等于2^(n-1)。

6. 快速幂取模

由于n可能很大(最大99999),直接计算2^(n-1)会溢出。使用快速幂算法,在O(log n)时间内完成模幂运算,结果对1,000,000,007取模。

复杂度分析

时间复杂度:O(n)

  • 构建邻接表:O(n),需要处理n-1条边
  • DFS遍历:O(n),每个节点访问一次
  • 快速幂计算:O(log n),相对于线性可忽略
  • 总体以DFS为主导,故为O(n)

空间复杂度:O(n)

  • 邻接表存储:O(n),存储n个节点的邻接关系
  • DFS递归栈:最坏情况O(n)(当树退化为链时)
  • 其他变量:O(1)
  • 总体空间消耗与节点数n成正比

这个解决方案高效地结合了树遍历和组合数学,通过一次DFS确定关键路径长度,再利用数学结论直接计算结果,避免了枚举所有可能的权值分配方案。

Go完整代码如下:

package main

import (
	"fmt"
)

func assignEdgeWeights(edges [][]int) int {
	n := len(edges) + 1
	g := make([][]int, n+1)
	for _, e := range edges {
		x, y := e[0], e[1]
		g[x] = append(g[x], y)
		g[y] = append(g[y], x)
	}

	var dfs func(int, int) int
	dfs = func(x, fa int) (d int) {
		for _, y := range g[x] {
			if y != fa { // 不递归到父节点
				d = max(d, dfs(y, x)+1)
			}
		}
		return
	}

	k := dfs(1, 0)
	return pow(2, k-1)
}

func pow(x, n int) int {
	const mod = 1_000_000_007
	res := 1
	for ; n > 0; n /= 2 {
		if n%2 > 0 {
			res = res * x % mod
		}
		x = x * x % mod
	}
	return res
}

func main() {
	edges := [][]int{{1, 2}, {1, 3}, {3, 4}, {3, 5}}
	result := assignEdgeWeights(edges)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

from typing import List

def assignEdgeWeights(edges: List[List[int]]) -> int:
    n = len(edges) + 1
    g = [[] for _ in range(n + 1)]
    for e in edges:
        x, y = e[0], e[1]
        g[x].append(y)
        g[y].append(x)
    
    def dfs(x: int, fa: int) -> int:
        d = 0
        for y in g[x]:
            if y != fa:  # 不递归到父节点
                d = max(d, dfs(y, x) + 1)
        return d
    
    k = dfs(1, 0)
    return pow(2, k - 1)

def main():
    edges = [[1, 2], [1, 3], [3, 4], [3, 5]]
    result = assignEdgeWeights(edges)
    print(result)

if __name__ == "__main__":
    main()

在这里插入图片描述

C++完整代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

int pow_mod(int x, int n, int mod) {
    long long res = 1;
    long long base = x;
    while (n > 0) {
        if (n % 2 == 1) {
            res = (res * base) % mod;
        }
        base = (base * base) % mod;
        n /= 2;
    }
    return res;
}

int assignEdgeWeights(vector<vector<int>>& edges) {
    int n = edges.size() + 1;
    vector<vector<int>> g(n + 1);
    for (auto& e : edges) {
        int x = e[0], y = e[1];
        g[x].push_back(y);
        g[y].push_back(x);
    }
    
    function<int(int, int)> dfs = [&](int x, int fa) -> int {
        int d = 0;
        for (int y : g[x]) {
            if (y != fa) { // 不递归到父节点
                d = max(d, dfs(y, x) + 1);
            }
        }
        return d;
    };
    
    int k = dfs(1, 0);
    return pow_mod(2, k - 1, 1000000007);
}

int main() {
    vector<vector<int>> edges = {{1, 2}, {1, 3}, {3, 4}, {3, 5}};
    int result = assignEdgeWeights(edges);
    cout << result << endl;
    return 0;
}

在这里插入图片描述

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。