没有上司的舞会
题目描述
某大学有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站这位老师深搜过程讲的很好,对初学者很友好,建议小伙伴们看看呀!链接在这里:没有上司的舞会