若一条简单路径
现在小红给定一棵结点总数为
你需要将每个字母填入一个树的结点,使得该树的权值最大,输出树的最大权值。
第一行输入一个长度为26的数组,表示每个字母的个数,保证总和为。
第二行输入一个整数,表示树的结点总数。
接下来行,每行输入两个整数
,表示树的一条边。
输出一个整数,表示树的最大权值。
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));
})();