结点选择(树形动态规划)C语言
问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
前面也说了,这道题笔者花了相当长的时间,但其实细究起来,最重要的就三个点:
1.建树
(但这道题并不是简单的单个头结点,每个结点只有一个父结点的那种普通的树,它实际是个无向图!)
2.递推式
(这个难度比较小),但是不太好解释 ,讲不清楚请原谅哈~~♪( ^ ∇ ^ *) ,直接写基本思路:
深度遍历每一个结点,每个结点都进行一次判断:
如果取这个结点,那么该结点的子结点就不取,如果不取该结点,那么它的子结点有两种情况:可以取,也可以不取!
于是有状态方程:
dp[x][0]表示x结点不选中时最大的权值,dp[x][1]表示x结点选中时最大的权值
状态转移方程:dp[x][1] = dp[x][1] + dp[u][0] (u为x的子结点)
dp[x][0] = dp[x][0] + max{dp[u][0],dp[u][1]}(u为x的子结点)
(看不懂就多看几遍,自己纸上画一下,花点时间总是能懂的。)
3。树(无向图)的遍历
(事实上,树的遍历还是比较容易的,只要注意多叉树与二叉树之间的转换就很容易实现,祥见上一篇博客的代码(这几个字是链接))
但是!无向图的遍历就复杂了好多,这也是这篇博客的重点!!!
因为网上能找到的的代码基本都是千篇一律,但那段代码笔者是真的看不懂~~
但功夫不负有心人,我终于找到了一篇好东西!!
链式前向星https://blog.csdn.net/lala__lailai/article/details/79249809
以上为链接!
在这(两)位大佬的帮助下!笔者终于搞懂了这段神奇的代码!!
但是很显然这种算法笔者很难学得会呀~~呜呜呜…
哎,讲得乱七八糟的,希望读者大大们能看懂~~
看不懂就动笔一步一步跟着代码走,相信你一定会豁(jing)然(wei)开(tian)朗(ren)的~~
以上!
</div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet"></div>