poj1947-第一道树形dp,哎,欲哭无泪
第一道树形dp,欲哭无泪。
不知道如何说,首先对树学习的不深,大学上课的时候这些东西考试内容很固定,学的时候又有点吃力,所以学的不是很深。其次对于dp,其实也就是计算里面的迭代,但是这个方面确实博大精深,我曾经也是浅尝则止,导致此题感觉越发困难。最后递归,这是我学习过程中,认为最不好理解的一个算法,很难想象,但是递归之美不是让你去想象,而是去分析,如何才能递归。。。
然而这道题目,这三方面的知识都用到了,必须欲哭无泪,看了好久,下不了手,还是硬着头皮去学习,去分析,写出自己的心得。
题目很好理解,就是一棵树,问问如何减去最少的边,得到一个含有p个节点的子树。。。
这题满足所谓的最优子问题,记忆化搜索等等,因此符合动态规划,不同的是,这个dp要在树上进行。
dp状态方程
dp[s][i]:记录s结点,要得到一棵j个节点的子树去掉的最少边数
考虑其儿子k
1)如果不去掉k子树,则
dp[s][i] = min(dp[s][j]+dp[k][i-j]) 0 <= j <= i
2)如果去掉k子树,则
dp[s][i] = dp[s][i]+1
总的为
dp[s][i] = min (min(dp[s][j]+dp[k][i-j]) , dp[s][i]+1 )
到这里就可以放手去实现了。。。
代码:
#include <iostream>
using namespace std;
#define nMax 152
#define inf 0x3fffffff
/*
dp[s][i]:记录s结点,要得到一棵j个节点的子树去掉的最少边数
考虑其儿子k
1)如果不去掉k子树,则
dp[s][i] = min(dp[s][j]+dp[k][i-j]) 0 <= j <= i
2)如果去掉k子树,则
dp[s][i] = dp[s][i]+1
总的为
dp[s][i] = min (min(dp[s][j]+dp[k][i-j]) , dp[s][i]+1 )
*/
int dp[nMax][nMax];
int son[nMax], brother[nMax], root, n, p;
bool fFather[nMax];
void dfs(int s)
{
int k ,tmp;
for (int i = 0; i <= p; ++ i)
{
dp[s][i] = inf;
}
dp[s][1] = 0;
k = son[s];
//printf("son[%d] = %d\n",s, k);
while(k)
{
dfs(k);
for (int i = p; i >= 1; -- i)
{
tmp = dp[s][i] + 1;
for (int j = 1; j < i; ++ j)
{
if (dp[k][i - j] + dp[s][j] < tmp)
{
tmp = dp[k][i - j] + dp[s][j];
}
}
dp[s][i] = tmp;
//printf("dp[%d][%d] = %d\n",s,i,tmp);
}
k = brother[k];
//printf("k = %d\n", k);
}
}
int solve()
{
int ans;
dfs(root);
ans = dp[root][p];
for (int i = 1; i <= n; ++ i)//若想自己独立为根,必须先与自己的父亲断绝关系。。所以除了根节点,其他的节点要想独立成根,成为最少去边数,必须先加上1
{
if (dp[i][p] + 1 <ans)
{
ans = dp[i][p] + 1;
}
}
return ans;
}
int main()
{
int s, t;
while (scanf("%d%d", &n, &p) != EOF)
{
memset(son, 0, sizeof(son));
memset(fFather, false, sizeof(fFather));
for (int i = 1; i < n; ++ i)
{
scanf("%d%d", &s, &t);
brother[t] = son[s];//记录同一个父亲下的上一个兄弟
son[s] = t;//记录这个父亲的当前的儿子
fFather[t] = true;//标示这个孩子有父亲,不是根
}
for (int i = 1; i <= n; ++ i)
{
if (!fFather[i])
{
root = i;
break;
}
}
printf("%d\n", solve());
}
return 0;
}
poj1947-第一道树形dp,哎,欲哭无泪相关推荐
- hdu 1520 Anniversary party(第一道树形dp)
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1520 Anniversary party Time Limit: 2000/1000 MS (Java ...
- 蓝桥杯节点选择(java)第一道树形dp分析
蓝桥杯 节点选择 问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多少? 输入格式 第一行包含一个整数 ...
- 【Codeforces Round #614(div2)】E-Xenon's Attack on the Gangs(树形dp)
一.题目链接 https://codeforces.com/contest/1293/problem/E 二.题意 给n个结点,n-1条无向边.即一棵树.我们需要给这n-1条边赋上0~n-2不重复的值 ...
- BZOJ 2133 切割(树形DP,树上背包)大概是本题全网第一篇题解 >_<【BZOJ 修复工程】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ 2133 切割这道题全网搜不到任何一篇题解 >_< 看评测记录也没有几个人AC- ...
- hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】
题目链接 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可. 具体实现过程比较复杂,很神奇的一个树形dp,下面给出一个含较详细 ...
- 动态规划 —— 树形 DP
[概述] 树形动态规划是在树的数据结构上的动态规划,在各个阶段呈现树状关系的时候可以采用树形 DP,其基本思想是由子节点的信息推出父节点的信息. 树形 DP 中,是通过以下 4 点树的特点来进行建图的 ...
- BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )
一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...
- 树形DP总结,持续更新
自己做了动态规划的题目已经有了一个月,但是成效甚微,所以来总结一下动态规划,希望自己能够温故知新.这个博客是关于树形dp的,动态规划的一类题目. 首先从最简单的树形DP入手,树形DP顾名思义就是一棵树 ...
- bzoj 4455: [Zjoi2016]小星星 树形dp+容斥原理
题意 给出一棵树和一个图,问有多少种方法把树的节点标号使得其在改图中至少有一棵生成树与原来的树是重构的. n<=17 分析 想到了容斥,但是没想到从哪里容斥... 显然题目给了两个限制,一个是原 ...
最新文章
- 2021年值得关注的5个RPA趋势
- Hibernate 多对多映射实列
- 网页加载出现没有合适的负载均衡器_终于讲清楚了,什么是负载均衡(Load balancing)...
- 周报速递丨《网络安全审查办法》修订发布;微信支持数字人民币支付
- PHP中的dirname
- ASP.Net 附加调试,aspnet_wp.exe进程不能启动解决办法 .
- linux 脚本返回值
- Linux 中如何启用和禁用网卡?
- collection.stream()以及collect()方法
- python配置文件转dict
- Spark MLlib 编程
- redis缓存队列+MySQL +php任务脚本定时批量入库
- CTP: 接收心跳超时Bug
- c语言寻找子字符串拷贝,C语言:字符串拷贝(截取)、查找
- 视觉机器学习20讲-MATLAB源码示例(13)-稀疏表示算法
- php中in array函数_php中in_array函数的用法
- 中央处理器(CPU)—— 控制器的功能和基本原理(微程序控制器(CU))
- 3250灵魂附体?诺基亚PureView概念机809
- 调用百度API实现人脸识别
- 切尔西为切赫提供新岗位 蓝军盼其“回家”