二叉苹果树

二叉苹果树

https://ac.nowcoder.com/acm/problem/50505

简化版的书上背包

思路:对于以任意节点为根的子树,可以将子树按与根相连的边分组,不同组内所有的子树的可能即为有特定价值与体积的物品。要求以1为根的所有子树中含有j条枝的最大权值树,问题可以转化为从按1为根分组的所有子树中选放入体积为j的背包的所有选法的maxn,然后即可以用分组背包的思路求解,每组中可不选,选第一个,选第二个,balabalabala...
【注】:分组背包问题循环遵循:(一般便于空间降维处理)
for(分组)
for(体积)
for(决策)

AC代码

#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define ll long long
#define ull unsigned long long
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define per(i, l, r) for (int i = l; i >= r; --i)
#define mset(s, _) memset(s, _, sizeof(s))
#define mcpy(s, _) memcpy(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define vi vector<int>
#define vpii vector<pii> 
#define mp(a, b) make_pair(a, b)
#define pll pair <ll, ll>
#define fir first
#define sec second
#define inf 0x3f3f3f3f
inline int lowbit(int x) {return x & -x;} 
template< typename T > inline void get_min(T &x, T y) {if(y < x) x = y;}
template< typename T > inline void get_max(T &x, T y) {if(x < y) x = y;}
inline int read() {
  int x = 0, f = 0; char ch = getchar();
  while (!isdigit(ch)) f |= ch == '-', ch = getchar();
  while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
  return f ? -x : x;
}
template<typename T> inline void print(T x) {
  if (x < 0) putchar('-'), x = -x;
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}
template<typename T> inline void print(T x, char let) {
  print(x), putchar(let);
}

const int N = 210, mod = 1e9 + 7;
int n, m;
int h[N], nex[N], v[N], w[N], idx;
void add(int a, int b, int c) {
    v[idx] = b; nex[idx] = h[a]; w[idx] = c; h[a] = idx ++ ;
}

int f[N][N];   
//f[i][j]:以i为根的子树中且含j条枝的所有方案的最大权值
void dp(int u, int fa) {
    for(int i = h[u]; ~i; i = nex[i]) {        //组别
        int e = v[i];
        if(e == fa) continue;
        dp(e, u);
        for(int j = m; j; j -- ) {    //体积 此处状态表示少开了一维组别,故从大到小枚举ti'ji
            for(int k = 0; k < j; k ++ ) { //决策
                f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e][k] + w[i]);                            
            }
        }
    }
} 

int main() {    
    mset(h, -1);
    cin >> n >> m; 
    rep(i, 1, n - 1) {
        int a, b, c; cin >> a >> b >> c;
        add(a, b, c); add(b, a, c); 
    }

    dp(1, -1);

    cout << f[1][m] << endl; 

    return 0;
}

代码转移方程说明
f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e][k] + w[i]);
因为进行了降维处理,故max运算左边代表不选当前这组,从当前组之前的组中选的最优解,
max运算右边代表选择当前这组,但因为此时还有一条与当前根相连的边要选上,故背包体积需要预留1单元,故为j - k - 1,而f[e][k]表示当前选择物品的价值

全部评论

相关推荐

迷茫的大四🐶:摊牌了,我是25届的,你们也不招我
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
正在热议
更多
# 你的mentor是什么样的人? #
4096次浏览 29人参与
# 你觉得mentor喜欢什么样的实习生 #
10394次浏览 288人参与
# 平安产险科技校招 #
2412次浏览 0人参与
# 帮我看看,领导说这话什么意思? #
6307次浏览 26人参与
# 没有家庭托举的我是怎么找工作的 #
12412次浏览 158人参与
# 怎么给家人解释你的工作? #
1425次浏览 16人参与
# 智慧芽求职进展汇总 #
18000次浏览 106人参与
# 求职低谷期你是怎么度过的 #
5263次浏览 92人参与
# 26届秋招公司红黑榜 #
12326次浏览 43人参与
# 从哪些方向判断这个offer值不值得去? #
6600次浏览 93人参与
# 同bg的你秋招战况如何? #
158823次浏览 927人参与
# 度小满求职进展汇总 #
10109次浏览 51人参与
# 实习必须要去大厂吗? #
146666次浏览 1541人参与
# 校招泡的最久的公司是哪家? #
4576次浏览 22人参与
# 你有哪些缓解焦虑的方法? #
37177次浏览 835人参与
# 面试紧张时你会有什么表现? #
1705次浏览 21人参与
# 你喜欢工作还是上学 #
77583次浏览 860人参与
# 入职第一天,你准备什么时候下班 #
85482次浏览 467人参与
# 秋招想进国企该如何准备 #
97710次浏览 487人参与
# 简历无回复,你会继续海投还是优化再投? #
103582次浏览 819人参与
# 机械人的工作环境真的很差吗 #
25034次浏览 119人参与
# 独居后,你的生活是更好了还是更差了? #
28126次浏览 263人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务