上一次的节点选择算法由于春节过年耽搁了,现在重新补上
- 经验教训
在纷繁复杂的使用了列表来暂存数据之后,发现其实可以利用笔者自己不太常用的字典遍历来减少内存占用,于是更新代码为:
n = int(input())
weight_list =[0] + list(map(int, input().split()))
aix_dict = {}
for i in range(1, n + 1):
aix_dict[i] = []
for i in range(n - 1):
a, b = list(map(int, input().split()))
aix_dict[a].append(b)
aix_dict[b].append(a)
def deep_copy(temp_dict):
dic = {}
for key in temp_dict:
dic[key] = temp_dict[key]
return dic
def dp(temp_dict):
score = 0
for key in temp_dict:
dic = deep_copy(temp_dict)
for k in dic[key]:
if k in dic.keys():
del dic[k]
del dic[key]
temp_score = 0
if dic == {}:
temp_score = weight_list[key]
else:
temp_score = weight_list[key] + dp(dic)
if score < temp_score:
score = temp_score
return score
print(dp(aix_dict))
这其中可以发现:
1、直接将dict作为迭代器遍历和取出他的keys遍历是一样的。
2、删除字典中的元素应当使用del函数。
3、判断一个键是否在字典中原先应当使用has_key的方法,但是python3.7似乎没有这个方法,使用key in dict.keys()的效果是一样的。
然而优化后的结果在测试点执行的时候依旧存在超时的问题。因此开始研究树形DP。
- 树形DP
树形DP给我的启发是很大的,首先附上代码:
def dfs(node,pre):
global value,table
for i in table.get(node):
if i !=pre:
dfs(i,node)
value[node][0]+=max(value[i][0],value[i][1])
value[node][1]+=value[i][0]
def main():
global value, table
n = int(input())
value = list(map(int, input().split()))
value = list(map(lambda x:[0,x],value))
value.insert(0,0)
table = {}
for i in range(n):
table.update({i + 1: []})
for i in range(n - 1):
father, child = list(map(int, input().split()))
table.get(father).append(child)
table.get(child).append(father)
dfs(1,0)
print(max(value[1][0],value[1][1]))
if __name__=='__main__':
main()
这个DP算法当中,通过更新value[n][2]这个二维列表来获取结果,最终要的是根节点上的值。通过0和1这个长度为2的维度来表示是否选择该节点,第一个维度则是用来标识根的。因为是树,所以只要确定了根节点,就能够知道所有的可以选择的节点。
另外,当确定了根节点之后,其余所有子节点之间是不会相邻的,这一点非常重要。这是树形DP的最核心的所在。
并且在我自己尝试DP算法的写法的时候,总是莫名其妙写成了纯粹的递归。忽略了将数组与递归函数分开存放这一美妙的方法(我总是想着遍历递归函数的返回值需要返回数组,却没想到可以为void,然后全局更新)。
此题非常具有借鉴意义,值得仔细回味。