公司要举办一个员工派对,公司里所有的员工都有资格来参加。该公司的组织结构是一个二叉树结构。如果一个节点A有双亲节点B,则代表B是A的上司。实际上,每一个员工为派对所能带来的贡献不一样,有的人幽默,就能使派对更加有趣,而有的人恰恰相反。树上每一个节点圆圈里的数字便代表每一个员工为派对所能带来的贡献值。然而,假如该公司里的所有员工都对自己的上司不满意(如果其有上司的话),那么如果一个员工来到派对,其上司就不能来到派对,反之亦然。但员工和员工上司的上司是可以一起参加派对的,因为他们互相不熟悉。如果你是董事长的秘书,并且已知公司组织结构,应该怎么邀请员工,使得任何一组员工和上司不会同时出现在派对中,并且使得邀请的所有员工的贡献值之和最大?
如图所示,邀请标为蓝色的员工来参加派对,其派对贡献值之和为10。
为每一个节点(员工)设两个值:如果邀请能得到的贡献值和不邀请能得到的贡献值。从最底层开始更新,因为最底层的员工只会影响到其上一层(上司)的到场。
以上图为例
(1)每一个节点的邀请值=该节点的贡献值+左子节点的不邀请值+右节点的不邀请值。
如果一个节点的员工被邀请,则其所有的子节点都不能被邀请,即要加上两个子节点的不邀请值。
(2)每一个节点的不邀请值=左子节点邀请值和不邀请值中的较大值+右子节点邀请值和不邀请值中的较大值。
如果一个节点的员工没有被邀请,则其子节点的员工既可被邀请也可以不被邀请,从而取二者中的最大值以求出最优解
class treenode: # 二叉树节点的定义
def __init__(self, val):
self.val = val # 该节点的贡献值
self.left = None # 左侧子节点
self.right = None # 右侧子节点
def ans(root):
at_val, ab_val = DFS(root) # at_val和ab_val分别存储root节点的邀请值和不邀请值
return max(at_val, ab_val) # 返回两个值中的最大值,此值为派对所能得到的最大贡献值
def DFS(node): # 参数为root节点,DFS方法通过递归返回root节点的邀请值和不邀请值
if (node == None): # 如果不存在现有的参数节点,返回邀请值和不邀请值为0,0
return 0, 0
left_at, left_ab = DFS(node.left) # 存储参数节点左子节点的邀请值和不邀请值
right_at, right_ab = DFS(node.right) # 存储参数节点右子节点的邀请值和不邀请值
# 邀请值和不邀请值的计算
# 每一个节点的邀请值=该节点的贡献值+左子节点的不邀请值+右节点的不邀请值
Attend_Value = int(node.val) + left_ab + right_ab # 求出参数节点的邀请值
# 每一个节点的不邀请值=左子节点邀请值和不邀请值中的较大值+右子节点邀请值和不邀请值中的较大值
Absent_Value = max(left_at, left_ab) + max(right_at, right_ab) # 求出参数节点的不邀请值
return Attend_Value, Absent_Value # 返回参数节点的邀请值和不邀请值
Input = input()
Input = [i for i in Input.split(' ')]
tree = []
# Input为存放输入的列表
for item in Input: # 循环将所有输入转换为treenode类
tmp = treenode(item)
tree.append(tmp)
cnt = 1
for item in tree: # 循环,在此之前cnt赋初值为1,tree是一个存有treenode类的列表
if item.val == "null":
continue
if 2 * cnt <= len(Input) and tree[2 * cnt - 1].val != "null": # 判断是否有左子节点
item.left = tree[2 * cnt - 1]
if 2 * cnt + 1 <= len(Input) and tree[2 * cnt].val != "null": # 判断是否有右子节点
item.right = tree[2 * cnt]
cnt += 1
# 调用DFS函数并打印结果
result = ans(tree[0])
print("最大贡献值:", result)
输入:
二叉树为
输出结果为: