poj_2486 动态规划
题目大意
N个节点构成一棵树,每个节点上有一个权重val[i], 从根节点root出发在树上行走,行走的时候只能沿着树枝行进。最多在树上走k步,每第一次到达某个节点j,可以获得val[j]的收益,求从root出发,最多走k步,可以得到的最大收益。
题目分析
树形结构+ 最优化问题,考虑使用动态规划来解决,树形动态规划的dp状态,第一维 dp[i][...]一般是指从i节点出发或者以i节点为根的xxxx。
/*dp[i][j][0] 表示从节点i出发,走j步,最终回到i节点,所能得到的最大收益
dp[i][j][1] 表示从节点i出发,走j步,最终不回到i节点,所能得到的最大收益
显然有:
(1)从i出发走j步回到i得到的最大收益 vs 依次枚举i的子节点son,从i出发走 j-k步回到i(其中不包括son节点),再
加上从son出发走k-2步,回到son节点,再加上i-->son 和 son-->i 的两步
dp[i][j][0] = max(dp[i][j][0], dp[i][j-k][0] + dp[son][k-2][0] + val[son])
(2)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步回到i(其中不包括son节点),再
加上从son出发走k-1步,不回到son节点,再加上i-->son的一步
dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][0] + dp[son][k-1][1] +val[son]);
(3)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步不回到i(其中不包括son节点),再
加上从son出发走k-2步,回到son节点,再加上i-->son和son-->i 的两步
dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);
以dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);为例,是否需要考虑 son节点走k-2步
和从son的父节点i开始走j-k步的重合? 答案是不需要,因为按照父节点i的子节点顺序,依次枚举son节点,在枚举到当前的son节点时,
dp[i][j-k][1]中不包含当前的son的贡献
*/
实现(c++)
#include<stdio.h>
#include<string.h>
#define MAX_NODE_NUM 205
#define MAX_STEP_NUM 205
#define max(a, b) a>b? a:b /*dp[i][j][0] 表示从节点i出发,走j步,最终回到i节点,所能得到的最大收益
dp[i][j][1] 表示从节点i出发,走j步,最终不回到i节点,所能得到的最大收益
显然有:
(1)从i出发走j步回到i得到的最大收益 vs 依次枚举i的子节点son,从i出发走 j-k步回到i(其中不包括son节点),再
加上从son出发走k-2步,回到son节点,再加上i-->son 和 son-->i 的两步
dp[i][j][0] = max(dp[i][j][0], dp[i][j-k][0] + dp[son][k-2][0] + val[son]) (2)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步回到i(其中不包括son节点),再
加上从son出发走k-1步,不回到son节点,再加上i-->son的一步
dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][0] + dp[son][k-1][1] +val[son]); (3)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步不回到i(其中不包括son节点),再
加上从son出发走k-2步,回到son节点,再加上i-->son和son-->i 的两步
dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]); 以dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);为例,是否需要考虑 son节点走k-2步
和从son的父节点i开始走j-k步的重合? 答案是不需要,因为按照父节点i的子节点顺序,依次枚举son节点,在枚举到当前的son节点时,
dp[i][j-k][1]中不包含当前的son的贡献
*/
int dp[MAX_NODE_NUM][MAX_STEP_NUM][2];
int val[MAX_NODE_NUM];
int n, k; struct Edge{
int v; //v表示该边所指向的子节点
int next; //next表示该边的兄弟边的索引
Edge(int vv = -1, int nn = -1):
v(vv), next(nn){
}
}; Edge gEdges[2*MAX_NODE_NUM]; //利用静态数组构建 多叉树
int gEdgeIndex;
int gHead[MAX_NODE_NUM]; //gHead[i] 表示节点i的最右边的子节点,初始时均为 -1 void InsertEdge(int u, int v){ //因为不能确定u和v在最终的树中哪个是父节点哪个是子节点
//因此分别将u和v作为父节点和子节点,形成边
gEdges[gEdgeIndex].v = v;
gEdges[gEdgeIndex].next = gHead[u];
gHead[u] = gEdgeIndex++;
} void Init(int n, int k){
for (int i = 1; i <= n; i++){
gHead[i] = -1;
for (int j = 1; j <= k; j++){
dp[i][j][0] = dp[i][j][1] = 0;
}
}
gEdgeIndex = 0;
} void Dfs(int u, int father){
for (int i = gHead[u]; i != -1; i = gEdges[i].next){
int v = gEdges[i].v;
if (v == father) //对于两个节点u和v,有u-->v的边,也有v-->u的边,为了避免死循环
continue;
Dfs(v, u); for (int j = k; j >= 0; --j){
for (int t = 1; j + t <= k; ++t){
dp[u][j + t][0] = max(dp[u][j + t][0], dp[u][j][1] + dp[v][t - 1][0] + val[v]);
if (t >= 2)dp[u][j + t][0] = max(dp[u][j + t][0], dp[u][j][0] + dp[v][t - 2][1] + val[v]);
if (t >= 2)dp[u][j + t][1] = max(dp[u][j + t][1], dp[u][j][1] + dp[v][t - 2][1] + val[v]);
}
}
}
}
int main(){
int u, v;
while (scanf("%d %d", &n, &k) != EOF){
Init(n, k);
for (int i = 1; i <= n; i++)
scanf("%d", &val[i]);
for (int i = 1; i < n; i++){
scanf("%d %d", &u, &v);
InsertEdge(u, v);
InsertEdge(v, u);
}
Dfs(1, -1);
printf("%d\n", dp[1][k][0] + val[1]);
}
return 0;
}
poj_2486 动态规划的更多相关文章
- 增强学习(三)----- MDP的动态规划解法
上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...
- 简单动态规划-LeetCode198
题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...
- 动态规划 Dynamic Programming
March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...
- 动态规划之最长公共子序列(LCS)
转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...
- C#动态规划查找两个字符串最大子串
//动态规划查找两个字符串最大子串 public static string lcs(string word1, string word2) { ...
- C#递归、动态规划计算斐波那契数列
//递归 public static long recurFib(int num) { if (num < 2) ...
- 动态规划求最长公共子序列(Longest Common Subsequence, LCS)
1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...
- 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划
[BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...
- POJ 1163 The Triangle(简单动态规划)
http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS Memory Limit: 10000K Total Submissi ...
随机推荐
- 非变动性算法源代码分析与使用示例( for_each、min_element 、find_if、search 等)
非变动性算法代码分析与示例: 一.for_each C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // TEMPLATE FUNCTION for_eac ...
- AutoFac文档9(转载)
目录 开始 Registering components 控制范围和生命周期 用模块结构化Autofac xml配置 与.net集成 深入理解Autofac 指导 关于 词汇表 关系类型 Autofa ...
- spring in action 9.1 spring security
spring security是基于spring AOP 和 Servlet 规范中的Filter 实现的安全框架. Spring Security 是为基于 Spring 的应用程序提供声明式安全保 ...
- 【死磕Java并发】-----J.U.C之AQS:CLH同步队列
此篇博客全部源代码均来自JDK 1.8 在上篇博客[死磕Java并发]-–J.U.C之AQS:AQS简单介绍中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个F ...
- 用注册表更改DNS的代码分享
用注册表更改DNS,1秒切换完毕,快速又方便,不用麻烦的去等待了,支持远程路劲运行 最进我这里DNS老是间歇性掉,很不稳定,广州地区,如果你的DNS经常需要更换,试试这个批处理, 论坛很多人发过了更改 ...
- NB 命令安装需似机(无图型化安装)
[root@ok ~]# virt-install -v -n 09ng04 -r 512 --vcpus=4 --location=/home/ISO/CentOS-6.7-x86_64-bin-D ...
- Node.js用fs.renameSync报cross-device link not permitted错
转自: http://blog.csdn.net/starrexstar/article/details/8048722 今天把 Manuel Kiessling 的[The Node Beginne ...
- Nginx 1.5.2 + PHP 5.5.1 + MySQL 5.6.10 在 CentOS 下的编译安装
最近配置了几台Web服务器,将安装笔记贴出来吧.没时间像以前那样,将文章写的那样系统了,请见谅.详细配置,可以看以前的旧文章: http://blog.zyan.cc/nginx_php_v6 .安装 ...
- python3+spark2.1+kafka0.8+sparkStreaming
python代码: import time from pyspark import SparkContext from pyspark.streaming import StreamingContex ...
- hdu1285 确定比赛名次(拓扑排序多种方法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 Problem Description 有N个比赛队(1<=N<=500),编号依次 ...