概述
题目大意:从一棵树上选取k个节点的子树使节点权值之和最大
思路: 想到是树形DP了但是一直推不出来状态状态转移方程,首先是自己状态如何表示都没想好
刚开始时用状态f[u][k][0]和f[u][k][1]表示以节点u父亲节点选k个节点0表示不选u,1表示选u,如果选u的话u的儿子至少要选一个,不选的话儿子可选可不选,
然后想想这样下边计算时就会越来越乱~~~
然后看了别人的思路:f[u][k]表示以u为根选k个节点的最大值,最后把所有的节点扫一遍就找到最大值了,真是简化了好多,实现时要用到01背包的思想,因为对于u的每个儿子,可以选择分 1,2,3…k-1 个节点给它
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = 105;
const int INF = 0x7f7f7f7f;
int num[maxn];
int vis[maxn], f[maxn][maxn], head[maxn];
int tot;
struct Eage
{
int to, next;
} eage[maxn*2];
int n, m;
inline void add(int x, int y)
{
eage[tot].to = y;
eage[tot].next = head[x];
head[x] = tot++;
}
void dfs(int x)
{
vis[x] = 1;
f[x][1] = num[x];
for (int i = head[x]; i !=-1 ; i = eage[i].next)
{
int v = eage[i].to;
if (!vis[v])
{
dfs(v);
for (int k = m; k >= 1; k--)
{
for (int j = 0; j < k; j++)//j从0到k-1
{
f[x][k] = max(f[x][k], f[x][k-j]+f[v][j]);
}
}
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
while (cin >> n >> m)
{
tot = 0;
memset(f, 0, sizeof(f));
memset(head, -1, sizeof(head));
memset(eage, 0, sizeof(eage));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++) scanf("%d", num+i);
int x, y;
for (int i = 1; i < n; i++)
{
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(0);
int ans = 0;
for (int i = 0; i < n; i++)
if (ans < f[i][m]) ans = f[i][m];
cout << ans << endl;
}
return 0;
}
最后
以上就是友好飞机为你收集整理的Zoj3201 Tree of Tree 树形DP的全部内容,希望文章能够帮你解决Zoj3201 Tree of Tree 树形DP所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复