题目类型:树形DP

传送门:>Here<

题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树。九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头吃几个随意。如果一个头吃了一个连通块,那么他们会把树枝也吃下去,获得边权那么多的难受值。先要吃完整棵树,使难受值总和最小

解题思路

首先会发现题目蕴含着一个奇妙的性质。会得到一条边的难受值当且仅当一条边相邻的两个节点是被同一个头吃的,换句话说如果相邻的两个节点是不同的龙吃的那么就不会获得该边的难受值。当我们确定大头吃的\(K\)个点之后,由于剩下的头每个头想吃几个就吃几个,由于给出了一颗树,一定存在一种方案使得任意两个相邻的点是不同的头。事实上,只需要多余的两种头就可以了。换句话说,我们可以把所有多余\(3\)个头的情况看做是\(3\)个头的。

当然需要特殊考虑\(M=2\)的情况,此时剩余的只有一个头了,需要特殊处理

于是,难受值完全取决于大头的那\(K\)个节点如何选择。

考虑树形DP:\(f[u][j][0/1]\)表示子树\(u\)中大头吃\(j\)个的最小难受值之和,其中\(k=0\)表示大头不吃根节点,反之亦然

于是可以发现我们只需要判断\(u,v\)的颜色是否相同即可以转移:当\(M>2\)时,除非\(u,v\)都是\(1\),否则不考虑。当\(M=2\)时,\(0,1\)可以直接表示他们的头了,所以也就是\(u ⊕ v\)

于是我们可以初步得到转移方程:$$f[u][j][1]=Min{f[v][k][0]+g[u][j-k][1],f[v][k][1]+g[u][j-k][1]+cost(u,v)}$$$$f[u][j][0]=Min{f[v][k][0]+g[u][j-k][0]+cost(u,v)*[M=2],f[v][k][1]+g[u][j-k][0]}$$

注意方程中的\(g\)数组,我们好像并没有涉及到它。事实上我们发现,方程的转移时需要枚举\(k\)作为中介的,但是众多儿子,每个儿子的\(k\)如何分配?题目给出了一颗多叉树,使得这一步非常复杂。

联想二叉树的做法,二叉树时当确定一个儿子是\(k\)时,马上就能确定另一个儿子是\(j-k\)。如果也用这种方式来处理多叉树就好了。于是我们在考虑第\(j\)个儿子的时候,可以记录前\(j-1\)个已经做过的儿子的最优值。而上一轮留下的结果正是\(f\)数组!但由于\(f\)数组在不断的更新,肯定不能直接拿过来用,因此需要一个临时数组\(g\)来记录上一轮的结果,其实形象的理解,就是把前面的\(j-1\)个儿子并在了一起

由于每一轮\(f\)数组都要重新更新,因此每一轮都要重新赋值\(+∞\)。另外很容易得到另个初始化条件:\(f[u][0][0]=1, f[u][1][1]=0\)。意义都很显然

Code

/*By DennyQi 2018.8.20*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 310;
const int MAXM = 610;
const int INF = 1061109567;
inline int read(){
int x = 0; int w = 1; register int c = getchar();
while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
if(c == '-') w = -1, c = getchar();
while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + c - '0', c = getchar();return x * w;
}
int N,M,K,x,y,z;
int first[MAXM],nxt[MAXM],to[MAXM],cost[MAXM],cnt;
int f[MAXN][MAXN][2], g[MAXN][2];
inline void add(int u, int v, int w){
to[++cnt]=v, cost[cnt]=w, nxt[cnt]=first[u], first[u]=cnt;
}
void DP(int u, int _f){
int v;
f[u][0][0] = f[u][1][1] = 0;
for(int i = first[u]; i; i = nxt[i]){
if((v = to[i]) == _f) continue;
DP(v, u);
for(int j = 0; j <= K; ++j){
g[j][0] = f[u][j][0];
g[j][1] = f[u][j][1];
f[u][j][0] = INF;
f[u][j][1] = INF;
}
for(int j = 0; j <= K; ++j){
for(int k = 0; k <= j; ++k){
f[u][j][1] = Min(f[u][j][1], f[v][k][0]+g[j-k][1]);
f[u][j][1] = Min(f[u][j][1], f[v][k][1]+g[j-k][1]+cost[i]);
if(M == 2){
f[u][j][0] = Min(f[u][j][0], f[v][k][0]+g[j-k][0]+cost[i]);
}
else{
f[u][j][0] = Min(f[u][j][0], f[v][k][0]+g[j-k][0]);
}
f[u][j][0] = Min(f[u][j][0], f[v][k][1]+g[j-k][0]);
}
}
}
}
int main(){
N = r, M = r, K = r;
if(M-1 + K > N){
printf("-1");
return 0;
}
for(int i = 1; i < N; ++i){
x = r, y = r; z = r;
add(x, y, z);
add(y, x, z);
}
memset(f, 0x3f, sizeof(f));
DP(1, 0);
printf("%d", f[1][K][1]);
return 0;
}

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

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

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

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

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

  3. vojis1523 NOI2002 贪吃的九头龙

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

  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. 9宫拼图小游戏(WPF MVVM实现)

    昨天逛论坛,看到一个哥们用WPF做了一个9宫的拼图游戏,发现初学WPF的人都很容易犯一个错误(我也犯过):把WPF当WINFORM用!所以想写一个比较符合WPF风格的版本,于是就抽工作的空余时间做了一 ...

  2. virtualenv虚拟环境的使用

    前提条件:安装好python环境并配置好环境变量(可参考另一篇博文,python安装及配置) 1.打开cmd命令终端 pip3 install virtualenvwrapper-win(我电脑上面已 ...

  3. PAT L3-016 二叉搜索树的结构

    https://pintia.cn/problem-sets/994805046380707840/problems/994805047903240192 二叉搜索树或者是一棵空树,或者是具有下列性质 ...

  4. centos安装bundle文件

    centos安装VMware-Workstation-Full-*.bundle那点事 | 鳗鱼是条狗https://kinggoo.com/centos-vmware.htm Linux 下 VMW ...

  5. 1170 - BLOB/TEXT column 'CustomerName' used in key specification without a key length

    [DTF] Data Transfer 企管宝_2_CRM start[DTF] Getting tables[DTF] Analyzing table: `CustomerInfo`[DTF] Ge ...

  6. 快速理解Git结构

      git pull:拉取远程服务器最新代码到本地(会自动merge) git add:将本地代码添加到暂存区 git commit:将暂存区的所有内容提交到当前分支(git会自动为我们创建第一个分支 ...

  7. [转帖]linux下的CPU、内存、IO、网络的压力测试

    linux下的CPU.内存.IO.网络的压力测试 https://www.cnblogs.com/zhuochong/p/10185881.html 一.对CPU进行简单测试: 1.通过bc命令计算特 ...

  8. Spring在web开发中的应用

    (1)在 web 项目中要使用 spring 需要导入一个 jar 包: spring-web-4.2.4.jar包 (2)在 web.xml 文件中配置 Listener <listener& ...

  9. Spark 数据倾斜

    Spark 数据倾斜解决方案 2017年03月29日 17:09:58 阅读数:382 现象       当你的应用程序发生以下情况时你该考虑下数据倾斜的问题了: 绝大多数task都可以愉快的执行,总 ...

  10. Django进阶知识

    drf学习之Django进阶点 一.Django migrations原理 1.makemigrattions: 相当于在每个app下的migrations文件夹下生成一个py脚本文件用于创建表或则修 ...