[codevs1746][NOI2002]贪吃的九头龙

试题描述

传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落。

有一天,有 \(M\) 个脑袋的九头龙看到一棵长有N 个果子的果树,喜出望外,恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把 \(N\) 个果子分成 \(M\) 组,每组至少有一个果子,让每个头吃一组。

这 \(M\) 个脑袋中有一个最大,称为“大头”,是众头之首,它要吃掉恰好 \(K\) 个果子,而且 \(K\) 个果子中理所当然地应该包括唯一的一个最大的果子。果子由 \(N-1\) 根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝“走到”任何一个其他的果子。

对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所有头吃掉的树枝的“难受值”之和。

九头龙希望它的“难受值”尽量小,你能帮它算算吗?

例如图 \(1\) 所示的例子中,果树包含 \(8\) 个果子,\(7\) 段树枝,各段树枝的“难受值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉 \(4\) 个果子,其中必须包含最大的果子。即 \(N=8\),\(M=2\),\(K=4\):

图一描述了果树的形态,图二描述了最优策略。

大头吃 \(4\) 个果子,用实心点标识;

小头吃 \(4\) 个果子,用空心点标识;

九头龙的难受值为 \(4\),因为图中用细边标记的树枝被大头吃掉了。

输入

输入文件 dragon.in 的第 \(1\) 行包含三个整数 \(N (1 \le N \le 300)\),\(M (2 \le M \le N)\),\(K (1 \le K \le N)\)。\(N\) 个果子依次编号 \(1,2, \cdots ,N\),且最大的果子的编号总是 \(1\)。第 \(2\) 行到第 \(N\) 行描述了果树的形态,每行包含三个整数 \(a (1 \le a \le N)\),\(b (1 \le b \le N)\),\(c (0 \le c \le 105)\),表示存在一段难受值为 \(c\) 的树枝连接果子 \(a\) 和果子 \(b\)。

输出

输出文件 dragon.out 仅有一行,包含一个整数,表示在满足“大头”的要求的前提下,九头龙的难受值的最小值。如果无法满足要求,输出 \(-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

输出示例

4

数据规模及约定

见“输入

题解

一开始看错题了,以为每个脑袋必须吃掉一个连通块,搞得我不知所措地以为还要树上双重背包。。。

由于树是一个二分图,所以当 \(m > 2\) 时总可以让除了“大头”外的脑袋不吃树枝,但 \(m = 2\) 时另一个脑袋也可能不得不吃树枝了。

那么就有一个显然的状态:\(f(i, j, k)\) 表示对于苹果树的子树 \(i\),其中 \(j\) 个被“大头”吃掉,\(k=1\) 时表示 \(i\) 号苹果被大头吃,\(k=0\) 时表示 \(i\) 号苹果被其他头吃。然后就是一个树上背包了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 310
#define maxm 610 int n, M, K, m, head[maxn], nxt[maxm], to[maxm], cost[maxm]; void AddEdge(int a, int b, int c) {
to[++m] = b; cost[m] = c; nxt[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; cost[m] = c; nxt[m] = head[a]; head[a] = m;
return ;
} int siz[maxn], f[maxn][maxn][2], tmp[maxn][2];
void upd(int& a, int b) {
if(a < 0) a = b;
else a = min(a, b);
return ;
}
void dp(int u, int fa) {
siz[u] = 1;
f[u][0][0] = f[u][1][1] = 0;
for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) {
dp(to[e], u);
rep(i, 0, siz[u] + siz[to[e]]) tmp[i][0] = tmp[i][1] = -1;
dwn(j, siz[u], 0) rep(s, 0, siz[to[e]]) {
if(f[u][j][0] >= 0 && f[to[e]][s][0] >= 0) upd(tmp[j+s][0], f[u][j][0] + f[to[e]][s][0] + cost[e] * (M == 2));
if(f[u][j][0] >= 0 && f[to[e]][s][1] >= 0) upd(tmp[j+s][0], f[u][j][0] + f[to[e]][s][1]);
if(f[u][j][1] >= 0 && f[to[e]][s][0] >= 0) upd(tmp[j+s][1], f[u][j][1] + f[to[e]][s][0]);
if(f[u][j][1] >= 0 && f[to[e]][s][1] >= 0) upd(tmp[j+s][1], f[u][j][1] + f[to[e]][s][1] + cost[e]);
}
siz[u] += siz[to[e]];
rep(i, 0, siz[u]) f[u][i][0] = tmp[i][0], f[u][i][1] = tmp[i][1];
}
// rep(i, 0, siz[u]) printf("f[%d][%d]: %d %d\n", u, i, f[u][i][0], f[u][i][1]);
return ;
} int main() {
n = read(); M = read(); K = read();
if(n < M + K - 1) return puts("-1"), 0;
rep(i, 1, n - 1) {
int a = read(), b = read(), c = read();
AddEdge(a, b, c);
} memset(f, -1, sizeof(f));
dp(1, 0); printf("%d\n", f[1][K][1]); return 0;
}

[codevs1746][NOI2002]贪吃的九头龙的更多相关文章

  1. [NOI2002]贪吃的九头龙(树形dp)

    [NOI2002]贪吃的九头龙 题目背景 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是 说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的 ...

  2. vojis1523 NOI2002 贪吃的九头龙

    描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天, ...

  3. [NOI2002] 贪吃的九头龙

    题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...

  4. Vijos1523 NOI2002 贪吃的九头龙 树形dp

    思路不算很难,但细节处理很麻烦 前面建图.多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述 #include <cstdio> #include < ...

  5. 洛谷 P4362 [NOI2002]贪吃的九头龙

    https://www.luogu.org/problemnew/show/P4362 首先有个很显然的dp:ans[i][j][k]表示i节点用j号头,i节点为根的子树中共有k个点用大头时i节点为根 ...

  6. Vijos1523贪吃的九头龙【树形DP】

    贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...

  7. 贪吃的九头龙(tyvj P1523)

    T2 .tyvj   P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...

  8. Vijos 1523 贪吃的九头龙 【树形DP】

    贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted ...

  9. codevs1746 贪吃的九头龙

    [问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...

随机推荐

  1. Spring 框架配置web.xml 整合web struts

    package cn.itcast.e_web; import java.io.IOException; import javax.servlet.ServletContext; import jav ...

  2. java基础必备单词讲解 day three

    if 如果 else 否则 switch 切换判断 case 实例 break 退出 return 返回 default 默认 variable array 数组 null 空的 无效的 pointe ...

  3. docker swarm使用keepalived+haproxy搭建基于percona-xtradb-cluster方案的高可用mysql集群

    一.部署环境 序号 hostname ip 备注 1 manager107 10.0.3.107 centos7;3.10.0-957.1.3.el7.x86_64 2 worker68 10.0.3 ...

  4. Ajax跨域请求以及乱码解决

    Ajax跨域请求2种解决方法 1 ) 什么叫跨域请求,协议,域名,端口号,其中一样不同都称跨域; 第一种:使用script标签发送请求; //创建一个script标签; var v_element=d ...

  5. vue学习笔记-:class

    当items.state为true时使用class='rad2state',否则为rad2(默认).

  6. javascript中string对象方法中的slice、substring、substr的区别联系

    1.slice.substring.snustr均属于String的对象方法,用于截取或提取字符串片段,三者均布破坏原先的字符串,而是以新的字符串返回被提取的部分. <script> va ...

  7. c#常用数据结构解析【转载】

    引用:http://blog.csdn.net/suifcd/article/details/42869341 前言:可能去过小匹夫博客的盆油们读过这篇对于数据结构的总结,但是小匹夫当时写那篇文章的时 ...

  8. tcl之array操作

  9. px与em的区别,权重的优先级

    px与em的区别,权重的优先级 PX特点:px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的.EM特点:1. em的值并不是固定的:2. em会继承父级元素的字体大小. 权重 ...

  10. JZOJ 5906. 传送门

    Description             8102年,Normalgod在GLaDOS的帮助下,研制出了传送枪.但GLaDOS想把传送枪据为己有,于是把Normalgod扔进了一间实验室.这间实 ...