探险 - 树型dp(背包)/多叉树转二叉树
题目大意:
国家探险队长 Jack 意外弄到了一份秦始皇的藏宝图,于是,探险队一行人便踏上寻宝之旅,去寻找传说中的宝藏。
藏宝点分布在森林的各处,每个点有一个值,表示藏宝的价值。它们之间由一些小路相连,小路不会形成环,即两个藏宝点之间有且仅有一条道路。探险队从其中的一点出发,每次他们可以留一个人在此点开采
宝藏,也可以不留,然后其余的人可以分成若干队向这一点相邻的点走去。需要注意的是,如果他们把队伍分成两队或两队以上,就必须留一个人在当前点,提供联络和通讯,当然这个人也可以一边开采此地的
宝藏。并且,为了节约时间,队伍在前往开采宝藏过程中是不会走回头路的。现在你作为队长的助理,根据已有的藏宝图,请计算探险队所能开采的最大宝藏价值。
注意:在整个过程中,每个人最多只能开采一个点的宝藏。
题目分析:
和选课差不多,可以转成孩子兄弟树,也可以按照拓扑序来进行树上背包(由于一个节点有多个儿子,所以选择由儿子更新父亲)。
\(dp[i][j][0]\)表示在i节点子树中选择j个节点,i节点不选的方案,\(dp[i][j][1]\)表示i节点子树中选择j个点,i节点要选的方案.
每个节点分为两种情况:在其父节点驻守,那么背包即可,否则由儿子直接转给父亲。
code
树上背包
#include<bits/stdc++.h>
using namespace std;
const int N = 150, M = 150;
int n, m, dp[N][M][2];
int ecnt, adj[N], go[N << 1], nxt[N << 1];
int val[N], fa[N], deg[N], ans;
queue<int> que;
inline void addEdge(int u, int v){
nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v;
}
inline void dfs(int u, int f){
fa[u] = f;
for(int e = adj[u]; e; e = nxt[e]){
int v = go[e];
if(v == f) continue;
dfs(v, u);
deg[u]++;
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
for(int i = 1; i < n; i++){
int x, y; scanf("%d%d", &x, &y);
addEdge(x, y), addEdge(y, x);
}
for(int j = 1; j <= n; j++)
for(int k = 1; k <= m; k++) dp[j][k][1] = val[j];
dfs(1, 0);
while(!que.empty()) que.pop();
for(int j = 1; j <= n; j++)
if(!deg[j]) que.push(j);
while(!que.empty()){
int u = que.front(); que.pop();
int tmp[M][2];
memcpy(tmp, dp[fa[u]], sizeof tmp);
for(int j = 1; j <= m; j++){
for(int k = m - j; k >= (fa[u] ? 1 : 0); k--){ //驻守在father
dp[fa[u]][k + j][1] = max(dp[fa[u]][k + j][1], tmp[k][1] + max(dp[u][j][1], dp[u][j][0]));
}
dp[fa[u]][j][0] = max(dp[fa[u]][j][0], max(dp[u][j][1], dp[u][j][0])); //不驻守
}
if(!(--deg[fa[u]]) && fa[u]) que.push(fa[u]);
}
printf("%d", max(dp[0][m][1], dp[0][m][0]));
return 0;
}
多叉树转二叉树
#include<bits/stdc++.h>
using namespace std;
const int N = 150;
int n, m;
int val[N], fa[N];
int ecnt, adj[N], nxt[N << 1], go[N << 1];
int dp[N][N][2], son[N], bro[N];
inline void addEdge(int u, int v){
nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v;
}
inline void dfs(int u, int f){
fa[u] = f;
for(int e = adj[u]; e; e = nxt[e]){
int v = go[e];
if(v == f) continue;
dfs(v, u);
}
}
inline int DP(int u, int k, int t){
if(!u || !k) return dp[u][k][t] = 0;
if(dp[u][k][t] != -1) return dp[u][k][t];
dp[u][k][t] = 0;
if(t == 1){ //父亲节点被选择
for(int i = 0; i <= k - 1; i++) //选择u
dp[u][k][1] = max(dp[u][k][1], DP(son[u], i, 1) + DP(bro[u], k - 1 - i, 1) + val[u]);
for(int i = 0; i <= k; i++) //不选u
dp[u][k][1] = max(dp[u][k][1], DP(son[u], i, 0) + DP(bro[u], k - i, 1));
}
else { //父亲节点未被选择 ,只能选择一边
dp[u][k][0] = max(dp[u][k][0], max(
max(DP(son[u], k - 1, 1) + val[u], DP(son[u], k, 0)),
DP(bro[u], k, 0)
));
}
return dp[u][k][t];
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
for(int i = 1; i < n; i++){
int x, y;
scanf("%d%d", &x, &y);
addEdge(x, y);
addEdge(y, x);
}
dfs(1, 0);
memset(dp, -1, sizeof dp);
for(int i = 1; i <= n; i++) bro[i] = son[fa[i]], son[fa[i]] = i;
printf("%d", max(DP(son[0], m, 1), DP(son[0], m, 0)));
}
探险 - 树型dp(背包)/多叉树转二叉树的更多相关文章
- 【XSY1905】【XSY2761】新访问计划 二分 树型DP
题目描述 给你一棵树,你要从\(1\)号点出发,经过这棵树的每条边至少一次,最后回到\(1\)号点,经过一条边要花费\(w_i\)的时间. 你还可以乘车,从一个点取另一个点,需要花费\(c\)的时间. ...
- 初学树型dp
树型DP DFS的回溯是树形DP的重点以及核心,当回溯结束后,root的子树已经被遍历完并处理完了.这便是树形DP的最重要的特点 自己认为应该注意的点 好多人都说在更新当前节点时,它的儿子结点都给更新 ...
- POJ3659 Cell Phone Network(树上最小支配集:树型DP)
题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...
- POJ 3342 - Party at Hali-Bula 树型DP+最优解唯一性判断
好久没写树型dp了...以前都是先找到叶子节点.用队列维护来做的...这次学着vector动态数组+DFS回朔的方法..感觉思路更加的清晰... 关于题目的第一问...能邀请到的最多人数..so ea ...
- 洛谷P3354 Riv河流 [IOI2005] 树型dp
正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...
- 【POJ 3140】 Contestants Division(树型dp)
id=3140">[POJ 3140] Contestants Division(树型dp) Time Limit: 2000MS Memory Limit: 65536K Tot ...
- Codeforces 581F Zublicanes and Mumocrates(树型DP)
题目链接 Round 322 Problem F 题意 给定一棵树,保证叶子结点个数为$2$(也就是度数为$1$的结点),现在要把所有的点染色(黑或白) 要求一半叶子结点的颜色为白,一半叶子结点的 ...
- ZOJ 3949 (17th 浙大校赛 B题,树型DP)
题目链接 The 17th Zhejiang University Programming Contest Problem B 题意 给定一棵树,现在要加一条连接$1$(根结点)和$x$的边,求加 ...
- BZOJ 1564 :[NOI2009]二叉查找树(树型DP)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
随机推荐
- 关于ES6(ES2015)的知识点详细总结
ECMAScript6 ECMAScript简称就是ES,你可以把它看成是一套标准,JavaScript就是实施了这套标准的一门语言,现在主流浏览器使用的是ECMAScript5. http://ba ...
- Mycat快速入门
1.Mycat介绍 Mycat 是一个开源的分布式数据库系统,是一个实现了 MySQL 协议的的Server,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以 ...
- 洛谷 P1644 跳马问题
P1644 跳马问题 题目背景 在爱与愁的故事第一弹第三章出来前先练练四道基本的回溯/搜索题吧…… 题目描述 中国象棋半张棋盘如图1所示.马自左下角(0,0)向右上角(m,n)跳.规定只能往右跳,不准 ...
- Android开发之搜芽项目的图片载入问题(使用Volley进行网络图片载入)
搜芽的移动开发这几天进度相对来说很的快. 可是美中不足的就是网络图片的载入问题. 我有两套方案: 1)沿用迅雷动漫的图片载入.迅雷动漫也是用的一个开源的库.可是不知道是我使用出了问题还是真的是它的问题 ...
- iOS_01_C语言简介
1.先学C语言的原因 * oc基于C. * oc 跟 C的思想和语法很多地方不太一样,而且OC能和C混用. * C 是所有编程语言中的经典,很多高级语言都是从C语言中衍生出来的,比如 C++,C#.O ...
- (转)ORA-01940: cannot drop a user that is currently connected 问题解析
删除数据库用户的时候经常会遇到这样的错误: ORA: cannot drop a user that is currently connected 原因是有程序在连接我们需要删除的用户,我们删除用户之 ...
- Loadrunner--参数化知识点及参数池策略
一.为何进行脚本参数化? 脚本在录制的时候,记录的参数都是常量值,这样,虚拟用户在执行同一个脚本,向服务器发送请求时,使用的都是同一个参数值,与实际不符.所以使用参数化技术. 二.参数化的逻辑? 对脚 ...
- Docker---(1)Docker 简介
原文:Docker---(1)Docker 简介 版权声明:欢迎转载,请标明出处,如有问题,欢迎指正!谢谢!微信:w1186355422 https://blog.csdn.net/weixin_39 ...
- 再记AE与AO的区别与联系
原文地址:转:ArcObjects与ArcEngine作者:梦游 ArcObjects(简称AO),一般都是指ArcGIS Desktop版本的组件开发集,即需要安装ArcGIS桌面版软件后才能安 ...
- async和await在项目中的应用
Async基础知识: async函数是ES7标准引入的语法,基于Generator函数实现的,也就是说是Generator函数的语法糖.什么是Generator函数?(留个坑) 返回值是Promise ...