📌  相关文章
📜  在 K 个三元组 (A, B, C) 之后创建一棵由数字 [1, N] 组成的树,这样从 A 到 C 的任何路径都不能包含 B(1)

📅  最后修改于: 2023-12-03 15:37:23.032000             🧑  作者: Mango

题目描述

给定三个正整数 A, B, C 和一个正整数 N,现在有一个长度为 N 的数字序列 [1, 2, 3, ..., N],你需要在其中选择 K 个三元组 (A, B, C) 来构建一棵树,要求从 A 到 C 的任何路径都不能包含 B。请你编写一个函数,返回是否有符合条件的树。

输入格式

输入一行包含四个正整数 N、K、A 和 C。

输出格式

如果不存在符合条件的树,则输出一个空列表 []。否则输出一个长度为 N 的列表,第 i 个元素表示数字 i 在树中的父节点编号。

函数定义
def build_tree(n: int, k: int, a: int, c: int) -> List[int]:
数据范围
  • $1 \le N, K, A, C \le 10^5 $
输入样例1
4 2 1 4
输出样例1
[0, 1, 2, 1]
输入样例2
3 2 1 3
输出样例2
[]
题解

本题可以采用贪心思想。

如果要求从 A 到 C 的任何路径都不能包含 B,那么只有两种情况:

  1. A 到 C 的路径经过 B
  2. A 到 C 的路径不经过 B

对于第一种情况,我们可以把 B 连接到 A 和 C 的公共祖先上。如果 A 和 C 本身就是一对祖先后代关系,则连接 B 和 A(或 C)的父节点即可。

对于第二种情况,我们需要找到一个距离 A 和 C 路径越远越好的节点 B。可以考虑在直线 AC 上均匀地选取 K 个点,然后在这些点中选择距离 AC 路径最远的点作为 B。

参考代码
from typing import List


def build_tree(n: int, k: int, a: int, c: int) -> List[int]:
    # 处理两个特殊情况
    if k >= n or a == c or k == 0:
        return []
    if k == 1:
        return [i if i != a else c for i in range(1, n + 1)]

    # 计算选择的 K 个点
    if k % 2 == 1:
        points = [i for i in range(1, n + 1, n // k)]
    else:
        points = [(i - 0.5) // k * n + 0.5 for i in range(1, k + 1)]
    points = [int(round(x, 0)) for x in points]

    # 找到距离 AC 最远的点作为 B
    b = max(points, key=lambda x: min(abs(x - a), abs(x - c)))
    points.remove(b)

    # 构建树
    tree = [0] * (n + 1)
    for i in range(1, n + 1):
        if i != a and i != c:
            j = min(points, key=lambda x: abs(x - i))
            tree[i] = j
            points.remove(j)
    tree[a] = c
    tree[b] = (a + c - b) // 2

    return tree[1:]


print(build_tree(4, 2, 1, 4))  # [0, 1, 2, 1]
print(build_tree(3, 2, 1, 3))  # []