ural 1018 Binary Apple Tree
1018. Binary Apple Tree
Memory limit: 64 MB
2 5 \ / 3 4 \ / 1 |
Input
Output
Sample
input | output |
---|---|
5 2 1 3 1 1 4 10 2 3 20 3 5 20 |
21 |
刚开始学树状dp,欢迎来喷。
有一颗苹果树,它的树枝符合完全二叉树。每个树枝上有一些苹果。节点标号为1~N(1为根节点)。现在因为树枝太多了,需要保留q根树枝。问最多能保留多少苹果。
题目给出的数据并没有按照跟节点到子节点的顺序给出,如何建树便一直困扰了我好久(战五渣-。-)。 最终借助结构体存放两个儿子的下标比较优美地建出来了。
接下来讲转移。显然我们不光要考虑节点,还要考虑以该节点为根的树选择了多少条边。
dp[t][k] : 已 t 为根的子树保留k条边(树枝)最多能保留多少条苹果。
由此我们可以发现如果在某个节点保留了k条边,有以下两种情况。
1:只选择一棵子树。那么dp[t][k] = max(dp[t.l][k-1] + w[t][t.l], dp[t.r][k-1] + w[t][t.r]) //意思是在该子树(左或右)选择k-1条边,并加上根节点到该子树的边。
2:选择两颗子树。那么就存在两条固定的边(根节点到其左右孩子的边),dp[t][k] = w[t][t.l] +w[t][t.r] + max(dp[t.l][j] + dp[t.r][k - j - 2]) /*(j : 0 ~ K-2)*/ 。
即左子树和右子树总共选择k-2条边。
由此,输出dp[1][q]就好。
#include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; struct Node { int l, r; }T[105]; int n, q; int dp[105][105], map[105][105]; void buildTree(int t) {//建树 int flag = 0; for (int i=0; i<=n; i++) { if (map[t][i] && !T[i].l && !T[t].r) {//!T[i].l不为父节点 if (!T[t].l) T[t].l = i; else T[t].r = i; flag = 1; } } if (flag) { buildTree(T[t].l); buildTree(T[t].r); } } void Tdp (int s) { if (T[s].l == 0) return ; Tdp(T[s].l); Tdp(T[s].r); for (int i=1; i<=q; i++) {//转移 dp[s][i] = max(dp[T[s].l][i-1] + map[s][T[s].l], dp[T[s].r][i-1] + map[s][T[s].r]); for (int j=0; j<i-1; j++) { dp[s][i] = max(dp[s][i], dp[T[s].l][j] + dp[T[s].r][i-j-2] + map[s][T[s].l] + map[s][T[s].r]); } } } int main () { cin >> n >> q ; int a, b, c; for (int i=1; i<n; i++) { cin >> a >> b >> c; map[a][b] = map[b][a] = c; } buildTree(1); Tdp(1); cout << dp[1][q] <<endl; return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。