[NOI2002]贪吃的九头龙(树形dp)
[NOI2002]贪吃的九头龙
题目背景
传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是 说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的 总数会远大于九,当然也会有旧头因衰老而自己脱落。
题目描述
有一天,有 M 个脑袋的九头龙看到一棵长有 N 个果子的果树,喜出望外, 恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把 N 个果子分成 M 组,每组至少有一个果子,让每个头吃一组。
这M个脑袋中有一个最大,称为“大头”,是众头之首,它要吃掉恰好 K 个 果子 ,而 且 K 个果子中理所当然地应该包括唯一的一个 最大的果子。 果子由 N-1 根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝 “走到”任何一个其他的果子。
对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个 头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么 这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所 有头吃掉的树枝的“难受值”之和。
九头龙希望它的“难受值”尽量小,你能帮它算算吗?
例如图 1 所示的例子中,果树包含 8 个果子,7 段树枝,各段树枝的“难受 值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉 4 个果子,其中必 须包含最大的果子。即 N=8,M=2,K=4:

图一描述了果树的形态,图二描述了最优策略。
输入输出格式
输入格式:
输入文件 dragon.in 的第 1 行包含三个整数 N (1<=N<=300),M (2<=M<=N), K (1<=K<=N)。 N个果子依次编号 1,2,...,N,且 最大 的果子的 编 号 总 是 1。第 2 行到第 N 行描述了果树的形态,每行包含三个整数 a (1<=a<=N),b (1<=b<=N), c (0<=c<=10^5105),表示存在一段难受值为 c 的树枝连接果子 a 和果子 b。
输出格式:
输出文件 dragon.out 仅有一行,包含一个整数,表示在满足“大头”的要求 的前提下,九头龙的难受值的最小值。如果无法满足要求,输出-1。
输入输出样例
输入样例#1: 复制
8 2 4
1 2 20
1 3 4
1 4 13
2 5 10
2 6 12
3 7 15
3 8 5
输出样例#1: 复制
4
说明
该样例对应于题目描述中的例子。
题解
一眼树形dp。
首先按照套路想了一下
\(dp[i][j][k]\)表示第\(i\)个节点,给第\(j\)个头,第\(j\)个头已有\(k\)个果子。
然而我们并不能确定第\(j\)个头的果子在哪里。
不好记录一条边连接的两端归哪个头。
且空间会炸起飞。
那么我们换一种套路。
\(f[i][j]\)表示第\(i\)个节点选\(j\)个给\(1\)号头。
但是其他头会对题目有影响啊。
可以说样例给的很套路了。
我给个\(m==2\),说明不给大头就给小头。
没得选择。
但实际上,如果有多个小头。就一定不会吃树枝。
因为当前点吃了是2号头。那么那个点的儿子让3号吃就可以了。
再往下的一层给2号。以此交替。
所以我们就可以用\(f[i][j][0/1]\)表示\(1\)号头取不取了。
因为其他的节点的贡献就在于\(m==2\)?边权:0。
那么转移为
for(int j=0;j<=k;j++)
{
for(int t=0;t<=j;t++){
f[x][j][0]=min(f[x][j][0],min(dp[j-t][0]+f[v][t][1],dp[j-t][0]+f[v][t][0]+(m==2)*e[i].v));
f[x][j][1]=min(f[x][j][1],min(dp[j-t][1]+f[v][t][0],dp[j-t][1]+f[v][t][1]+e[i].v));
}
}
//注意这里的f数组不会及时更新。要用dp数组先代替。因为f越来越小对后面的选择会有后效性。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=305;
int n,m,k,f[N][N][2],dp[N][2];
struct node{
int to,nex,v;
}e[N<<1];
int num,head[N];
int read(){
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
void add(int from,int to,int v){
num++;
e[num].to=to;
e[num].v=v;
e[num].nex=head[from];
head[from]=num;
}
void dfs(int x,int fa){
f[x][1][1]=f[x][0][0]=0;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(v==fa)continue;
dfs(v,x);
for(int j=0;j<=k;j++){
dp[j][0]=f[x][j][0];
dp[j][1]=f[x][j][1];
}
memset(f[x],63,sizeof(f[x]));
for(int j=0;j<=k;j++){
for(int t=0;t<=j;t++){
f[x][j][0]=min(f[x][j][0],min(dp[j-t][0]+f[v][t][1],dp[j-t][0]+f[v][t][0]+(m==2)*e[i].v));
f[x][j][1]=min(f[x][j][1],min(dp[j-t][1]+f[v][t][0],dp[j-t][1]+f[v][t][1]+e[i].v));
}
}
}
}
int main(){
n=read();m=read();k=read();
if(m-1>n-k){printf("-1");return 0;}
for(int i=1;i<n;i++){
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
memset(f,63,sizeof(f));
dfs(1,0);
printf("%d\n",f[1][k][1]);
return 0;
}
[NOI2002]贪吃的九头龙(树形dp)的更多相关文章
- Vijos1523 NOI2002 贪吃的九头龙 树形dp
思路不算很难,但细节处理很麻烦 前面建图.多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述 #include <cstdio> #include < ...
- [codevs1746][NOI2002]贪吃的九头龙
[codevs1746][NOI2002]贪吃的九头龙 试题描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时 ...
- vojis1523 NOI2002 贪吃的九头龙
描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天, ...
- [NOI2002] 贪吃的九头龙
题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...
- 洛谷 P4362 [NOI2002]贪吃的九头龙
https://www.luogu.org/problemnew/show/P4362 首先有个很显然的dp:ans[i][j][k]表示i节点用j号头,i节点为根的子树中共有k个点用大头时i节点为根 ...
- Vijos 1523 贪吃的九头龙 【树形DP】
贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted ...
- Vijos1523贪吃的九头龙【树形DP】
贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...
- 贪吃的九头龙(tyvj P1523)
T2 .tyvj P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...
- codevs1746 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- springboot的几个缓存相关注解
@Cacheable:查询 几个属性: cacheNames/value:指定缓存组件的名字: key:缓存数据使用的key,可以用来指定.默认即使用方法参数的值 keyGenerator ...
- 外网主机如何将数据包发送到共用一个公网IP的局域网某特定主机上的
内网的一台电脑要上因特网对外开放服务或接收数据.都须要port映射.port映射分为动态和静态. 动态port映射:内网中的一台电脑要訪问站点.会向NAT网关发送数据包.包头中包含对方站点IP.por ...
- cocos2d-x 中XML解析与数据存储
一不小心就玩了一周的游戏了.哎.玩的时候时间过得总是这么快... 于是今天决定看一下之前不怎么非常熟悉的XML;(之前做游戏时数据的储存用到过XML,但这块是还有一个同事在做,所以不怎么熟悉), 看了 ...
- java.lang.ClassNotFoundException: org.jaxen.JaxenException
java.lang.ClassNotFoundException: org.jaxen.JaxenException java.lang.ClassNotFoundException: org.jax ...
- 【BUG】android.content.res.Resources$NotFoundException: File res/drawable-xxhdpi/toolbar_line.png from
SafeGod在coolpad(4.0)上执行.登陆进去的设备列表界面遇到的问题.三星和索尼没有这个问题. 06-24 15:23:06.897: E/AndroidRuntime(12655): F ...
- PHP中用下标符号[]去读取字符串的逻辑
PHP中 [(下标)] 符号不仅能够应用于数组和对象,还能够应用于字符串,假设不注意非常easy出错. 比方获取一个网络接口,正常情况下会返回一个数组结构的json,经过解析之后结果为: array( ...
- C++字符串操作笔试题第二波
//1.字符串替换空格:请实现一个函数,把字符串中的每一个空格替换成"%20". //比如输入"we are happy.".则输出"we%20are ...
- Win10使用VMware虚拟机安装ubuntu
Win10专业版自带有虚拟机安装工具Hyper-V,也可以使用其他如VMware工具安装,也挺方便. 所需工具: 1. VMware-workstation 下载链接: http://rj.bai ...
- 高级程序员与CTO技术总监首席架构师
一.高级程序员 如果你是一个刚刚创业的公司,公司没有专职产品经理和项目经理,你就是公司的产品经理,你如果对你现在的开发员能力不满,那么你只需要的是一个高级程序员. 你定义功能.你做计划推进和管理,他可 ...
- correct ways to define variables in python
http://stackoverflow.com/questions/9056957/correct-way-to-define-class-variables-in-python later say ...