#123-[树形动态规划]二叉苹果树

版权声明:反正也没有人会转,下一个 https://blog.csdn.net/drtlstf/article/details/83011082

Description

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)。这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。

Input

第1行2个数,N和Q(1<=Q<= N,1<N<=100)N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。

Output

一个数,最多能留住的苹果的数量。

Sample Input

5 2
1 3 1
1 4 10
2 3 20
3 5 20

Sample Output

21

树形DP的一道很经典的题.

#include <iostream>
#include <vector>

#define SIZE 110

using namespace std;

struct edge
{
	int to, cap;
};

vector<edge> graph[SIZE];
int dp[SIZE][SIZE], m; // DP[I][J]表示第I个节点和它的子树保留J个树枝剩余苹果的最大值.

int dfs(int u, int pre) // DP过程
{
	int i, j, k, v, w, childcount = 0;
	
	for (i = 0; i < graph[u].size(); ++i)
	{
		v = graph[u][i].to;
		if (v == pre) // 确保不是回到了前一个点
		{
			continue;
		}
		w = graph[u][i].cap;
		childcount += dfs(v, u) + 1;
		for (j = min(childcount, m); j >= 1; --j)
		{
			for (k = min(j, childcount); k >= 1; --k)
			{
				dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k-1] + w); // 条件转移方程
			}
		}
	}
	
	return childcount; // 顺便返回二子数
}

int main(int argc, char** argv)
{
	int n, u, v, w, i;
	
	scanf("%d%d", &n, &m);
	for (i = 1; i < n; ++i)
	{
		scanf("%d%d%d", &u, &v, &w);
		graph[u].push_back({v, w}); // 建图
		graph[v].push_back({u, w});
	}
	
	dfs(1, -1);
	
	printf("%d", dp[1][m]);
		
	return 0;
}

猜你喜欢

转载自blog.csdn.net/drtlstf/article/details/83011082