首页 > 试题广场 >

树的最大权值

[编程题]树的最大权值
  • 热度指数:89 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红定义一棵树的权值为:
若一条简单路径 u\rightarrow v 满足 s_u+...+s_v 是一个回文串。在所有这样的路径中,路径的长度的最大值是是该树的权值。
现在小红给定一棵结点总数为 n 的树和 'a','b','c',...,'z'每种字母的个数,保证所有个数之和恰好等于 n
你需要将每个字母填入一个树的结点,使得该树的权值最大,输出树的最大权值。

输入描述:
第一行输入一个长度为26的数组,表示每个字母的个数,保证总和为 n

第二行输入一个整数 n(1\leq n\leq 10^5),表示树的结点总数。

接下来 n-1 行,每行输入两个整数 u,v(1\leq u,v\leq n,u\neq v),表示树的一条边。


输出描述:
输出一个整数,表示树的最大权值。
示例1

输入

1 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
5
1 2
2 3
3 4
4 5

输出

3
首先可以根据给出的数组来求出理论上最长的回文串,如果字母是偶数个数肯定可以加入回文串,
然后字母是奇数个的话,可以取出一个来当回文串的中间,
然后剩下的就是偶数个的可以加入回文串
然后就是遍历这个无向图,枚举一个点作为树的直径的转折点,
然后枚举这个点的邻居的最长路径和次长路径,那么答案就是max(最长路径+次长路径,理论上最长长度)


const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // 读取每种字母的个数
    let counts = (await readline()).split(" ").map(Number);

    let n = parseInt(await readline());

    // 构建树
    let adj = Array.from({ length: n + 1 }, () => []);
    for (let i = 0; i < n - 1; i++) {
        let [u, v] = (await readline()).split(" ").map(Number);
        adj[u].push(v);
        adj[v].push(u);
    }

    // 计算可以构成回文串的最大长度
    let maxPalindromeLength = 0;
    let hasOdd = false;
    for (let count of counts) {
        maxPalindromeLength += Math.floor(count / 2) * 2;
        if (count % 2 === 1) {
            hasOdd = true;
        }
    }
        //取出一个奇数个数的字符当回文串中间的
    if (hasOdd) {
        maxPalindromeLength++;
    }

    // 计算树的直径
    let treeDiameter = 0;

    function dfs(u, fa) {
        let dist = 0;
        //最长路径
        let d1 = 0;
        //次长路径
        let d2 = 0;
        for (let v of adj[u]) {
            if (v === fa) continue;
            let d = dfs(v, u) + 1;
            if (d >= d1) {
                d2 = d1; // 原来的最长变次长
                d1 = d; // 更新最长
            } else if (d >= d2) {
                d2 = d; // 更新次长
            }
            dist = Math.max(dist, d);
        }
        // 更新最大和次大加起来的最大值
        treeDiameter = Math.max(treeDiameter, d1 + d2);
        return dist;
    }

    dfs(1, -1);

    // 答案是理论最大回文长度和树直径+1的最小值
    console.log(Math.min(maxPalindromeLength, treeDiameter + 1));
})();

发表于 2025-08-02 15:00:12 回复(0)
路径长度的定义不是边的数量吗?答案是按照点的数量来的?
发表于 2025-07-03 18:13:00 回复(0)