搜集钻石(树形DP例题)

3 篇文章 0 订阅
2 篇文章 0 订阅

搜集钻石

Description

 

蒜国有 n 座城市,编号从 1 到 n,城市间有 n−1 条道路,且保证任意两座城市之间是连通的。每一座城市有一定数量的钻石。

蒜头君想在蒜国搜集钻石。他从城市 1 出发,每天他可以通过城市之间道路开车到另外的城市。当蒜头第一次到一个城市的时候,他可以搜集完这个城市的所有钻石,如果他后面再来到这个城市,就没有砖石可以收集了。

蒜头君只有 K 天时间,请你帮算蒜头君计算他最多可以搜集多少钻石。

Input

 

第一行输入三个整数 n(1≤n≤100),K(0≤k≤200),表示一共有 n 座城市,蒜头君有 K 天时间。

接下里一行输入 n 个用空格隔开的整数,表示每个城市的钻石数量。每个城市的钻石数量不大于 1000。

接下来输入 n−1 行,每行输入两个整数 a(1≤a≤n),b(1≤b≤n),表示城市 a和城市 b 之间存在一条双向道路。

Output

输出一行一个整数表示蒜头君最大能获取的钻石数量。
 

Sample Input:

3 2
3 8 3
1 3
3 2


Output:

14

树形DP。

dp[i][j][0/1]:现节点为i,用了j天,0表示不回去,1表示回去。

#include <bits/stdc++.h>
#define For(i, j, k) for(int i = (j); i <= (k); i++)

using namespace std;
int n;
const int MAXN = 205;
struct Edge {
	int v, nxt;
}e[MAXN << 1];
int lst[MAXN], tott = 0, m;
inline void addedge(int u, int v) {
	e[++tott].v = v;
	e[tott].nxt = lst[u];
	lst[u] = tott;
}
int val[MAXN];
int dp[MAXN][MAXN][2];//DP[i][j][k]:第i个点,已经用了j天,1回来,0不回 
void dfs(int u, int fa) {
	For(i, 0, m) dp[u][i][1] = dp[u][i][0] = val[u]; //先把dp[u][i]初始值赋为val 
	for(int i = lst[u]; i; i = e[i].nxt) { //枚举u的每一条出边 
		int v = e[i].v;
		if(v != fa) {
			dfs(v, u);
			for(int j = m; j >= 1; j--) {  //当前点现在有几天 
				For(e, 0, j-1) {//当前点推来时走了e天 
					if(j - e >= 2) {
						dp[u][j][1] = max(dp[u][j][1], dp[u][e][1] + dp[v][j-e-2][1]); // 如果当前这个点回去,则其子节点也必须回去 
						dp[u][j][0] = max(dp[u][j][0], dp[u][e][0] + dp[v][j-e-2][1]);// 如果当前点不回去,但子树v全部回去 
					}
					dp[u][j][0] = max(dp[u][j][0], dp[u][e][1] + dp[v][j-e-1][0]);//当前点出去就不回来了 ,剩下的e天回去 
				}
			}
		}
	}
}
int main()
{
	cin >> n >> m;
	For(i, 1, n) {
		scanf("%d", &val[i]);
	}
	For(i, 1, n-1) {
		int u, v;
		scanf("%d %d", &u, &v);
		addedge(u, v);
		addedge(v, u);
	}
	dfs(1, -1);
	cout << dp[1][m][0] << endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值