2021-04-17 阿里实习生笔试 第二题 树形01背包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 将城堡视为结点,道路视为边,则是一个图问题
  • n个结点,n-1条边,且所有结点都相连,说明该图是一棵无根树
  • 为了方便,将该树的根视为第1个结点。
  • 玉皇大帝最后要回到根节点,等价于将T除以2。
  • 在T的最大时间内获得最大的点权值之和,即是一个树形01背包问题。

定义d[i][j][k]为以结点i为根的子树,考虑前j棵子树,最大时间是k的最大价值。然后空间压缩即可。树形01背包可以参考洛谷P2014

#include "bits/stdc++.h"
using namespace std;
const int MAXN = 505;
int n, T;
int a[MAXN];
unordered_map<int,int> g2[MAXN];
vector<pair<int, int>> g[MAXN];
long long d[MAXN][205] = { 0 };
void create_tree(int i) {
	for (const auto& e : g2[i]) {
		g2[e.first].erase(i);
		create_tree(e.first);
	}
}
void dfs(int i) {
	d[i][0] = max(0, a[i]);
	for (int j = 0; j < g[i].size(); ++j) {
		int to = g[i][j].first;
		int to_t = g[i][j].second;
		dfs(to);
		for (int t = T; t >= 0; --t) {
			for (int k = 0; k + to_t <= t; ++k) {
				d[i][t] = max(d[i][t], d[i][k] + d[to][t - k - to_t]);
			}
		}
	}
}
int main() {
	cin >> n >> T;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	for (int i = 1; i < n; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		g2[u][v] = w;
		g2[v][u] = w;
	}
	create_tree(1);
	for (int i = 1; i <= n; ++i) {
		g[i] = vector<pair<int, int>>(g2[i].begin(), g2[i].end());
	}
	T /= 2;
	dfs(1);
	cout << d[1][T] << endl;
}
/*
2 1
1 1
1 2 1

2 2
1 1
1 2 1

3 0
1 1000 1000
1 2 0
3 1 0
*/
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值