[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 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- JS中检测数据类型的多种方法
面试当中经常会问到检测 js 的数据类型,我在工作当中也会用到这些方法.让我们一起走起!!! 首先给大家上一个案例 console.log(typeof "langshen"); ...
- Flask-Babel 使用简介(翻译文档)
最近用flask-bable翻译一个项目,在网站上查找到有一个示例文档,地址:http://translations.readthedocs.io/en/latest/flask-babel.html ...
- StringUtils 的填充方法
注意:两个参数的用空格填充,三个参数的用后面的参数填充 第一个参数要填充的字符串,第二个是需要的长度,第三个是以什么填充. 左侧填充: leftPad(): StringUtils.leftPad(S ...
- 【BZOJ 1221】 [HNOI2001] 软件开发
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] /* 设一个超级源点S和超级汇点T S和2*i-1各连一条容量为ni的边. 花费为0 表示每天都会产生ni条要洗的毛巾 S和2*i各 ...
- 我一不小心把ubuntu里的ps这样的命令删掉了,应该怎么重装呢
sudo apt-get --reinstall install procps
- ASP.NET-ActionResutlt
@RenderPage("Page_part1"); 上面的这种写法是错误的应该是 @RenderPage("Page_part1.cshtml"); // 要 ...
- 洛谷——P2822 组合数问题
https://www.luogu.org/problem/show?pid=2822 题目描述 组合数C_n^mCnm表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三 ...
- Android sdCard路径问题
一,获取Android设备的全部存储设备,这里边肯定有一个能用的 StorageManager sm = (StorageManager) context.getSystemService(Conte ...
- Bootstrap全局CSS样式之表单
.form-control--将单独的表单控件赋予一些全局样式,如默认宽度width:100%. .form-group--包裹表单控件,获得最好的排列: .form-inline--将表单设置为内联 ...
- DICOM医学图像处理:fo-dicom网络传输之 C-Echo and C-Store
背景: 上一篇博文对DICOM中的网络传输进行了介绍.主要參照DCMTK Wiki中的英文原文.通过对照DCMTK与fo-dicom两个开源库对DICOM标准的详细实现,对理解DICOM标准有一个更直 ...