没有上司的舞会 python题解(树形dp)

没有上司的舞会

题目描述
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

输入格式:
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0 0

输出格式:
输出最大的快乐指数。

输入:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

输出:
5

该题是一道典型的树形DP,主要考察动态规划与树形结构结合的用法,本题利用的是dfs深度优先搜索和后序遍历。

解题思路:

职员和上司不能同时参加舞会。
两种情况:一种是上司参加,则该上司的职员不能参加;
另一种是上司不参加,则该上司的职员可以参加也可以不参加。
确定状态:dp[u][0]指以u为根节点的子树,u不参加时该子树最大的快乐指数
dp[u][1]指以u为根节点的子树,u参加时该子树的最大的快乐指数。
状态转移:回溯的时候进行累加更新u节点的快乐值,s代表u的子节点
dp[u][0]+=max(dp[s][0],dp[s][1])
dp[u][1]+=dp[s][0]
核心dfs代码

def dfs(u):
    dp[u][1]=r[u]#对dp[u][1]进行初始化,r[u]代表u号职员的快乐指数
    for i in range(len(tree[u])):#len(tree[u])代表u节点的子节点的数量
        s=tree[u][i]#u的子节点
        dfs(s)#对子节点进行深搜
        dp[u][0]+=max(dp[s][0],dp[s][1])#回溯的过程,对每颗子树父节点的值进行累加更新
        dp[u][1]+=dp[s][0]
    return max(dp[u][0],dp[u][1])

推导过程:
在这里插入图片描述

该题完整python代码如下:有详细注释

N=int(input())
r={}
for i in range(1,N+1):
    ri=int(input())
    r[i]=ri

tree={}#tree代表用以父节点为key,子节点构成的列表为value的字典存放这棵树
l=[]#将[L,K]以列表的形式存放起来
for i in range(N-1):
    L,K=map(int,input().split())
    l.append([L,K])
    tree[L]=tree.get(L,[])
    tree[K]=tree.get(K,[])
    tree[K].append(L)
f={}
#f代表以用子节点为key,以父节点构成的列表为value的字典存放这棵树,为了便于后面找出父节点。
#value列表长度为0的key就是这棵树的根节点(根节点没有父节点)
for item in l:
    L,K=item[0],item[1]
    f[L]=f.get(L,[])
    f[K]=f.get(K,[])
    f[L].append(K)
# print(tree)
a,b=map(int,input().split())
dp=[[0 for i in range(2)]for j in range(N+1)]
def dfs(u):
    dp[u][1]=r[u]#对dp[u][1]进行初始化
    for i in range(len(tree[u])):
        s=tree[u][i]#u的子节点
        dfs(s)#对子节点进行深搜
        dp[u][0]+=max(dp[s][0],dp[s][1])#回溯的过程,对每颗子树父节点的值进行累加更新
        dp[u][1]+=dp[s][0]
    return max(dp[u][0],dp[u][1])

# 找到根节点,对根节点进行递归搜索
for key in f.keys():
    if len(f[key])==0:
        print(dfs(key))

B站这位老师深搜过程讲的很好,对初学者很友好,建议小伙伴们看看呀!链接在这里:没有上司的舞会

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值