题目链接:https://vijos.org/p/1144

woc我竟然A了,这道经典的树形dp或者说是树形dp的入门题我终于过了,虽然之前做过一些树形dp的题,但是这题开始还是一脸懵逼,dp方程如何定义都知道,但是不懂转移啊,这就有点伤了。。

dp方程定义dp[i][1]节点i 选自己

     dp[i][2]节点i选自己的儿子==不选自己和父亲

    dp[i][3]节点i选自己的父亲==不选自己选父亲

然后就是转移了。。毕竟是基础题嘛,所以转移也不难

转移的时候我们是直接递归到叶节点然后再做前面的。。所以我们不用考虑父节点的状态

dp[i][1]选自己的时候,儿子节点就有两种方式,选儿子自己,或者选儿子的父亲dp[i][1]+=min(dp[son][1],dp[son][3]);

dp[i][2]选儿子时 ,儿子就选或不选两个方式,但是如果一旦所有的儿子都是不选了,我们就要找一个最小的儿子树的值在最后加上,

dp[i][2]+=min(dp[son][1],dp[son][2])如果全部选了2,就要在结尾加上dp[i][2]+=min(dp[son][1]-dp[son][2])

至于为啥加这个,就是这道题唯一有点思考难度的地方了,因为你是要加最小的儿子选一个的值,所以找到最小,比如时第s2个儿子,之前已经加了dp[s2][2],所以最后的时候是加上dp[s2][1]-dp[s2][2],相当于把之前的那个dp[s2][2]抵消了,就不会加重复

dp[i][3]选父亲时,因为我们是从子往父推,所以不从父亲转移,就考虑这时候的儿子节点,儿子节点来源就是儿子自己放和儿子的儿子放

dp[i][3]+=min(dp[son][1],dp[son][2]);

好吧这就是这道题的全部了,最后只需要输出根节点的选自己和选儿子方案的最小值就可,因为根没有父亲。。。

储存这个关系的方式有两种,一种是链表,一种是多叉树转二叉树,

两种方式的不同点在于链表是双向的,然后重新建树,默认1为根节点

而多叉树转二叉树是以题目给的关系建树,以没有父亲的点为根

链表:

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#define maxn 1505
using namespace std; int f[maxn][],n;
struct edge{
int u,v,w,nxt;
}e[maxn*];
int a[maxn],head[maxn],vis[maxn],tot; void adde(int u,int v){
tot++;
e[tot].u=u;e[tot].v=v;
e[tot].nxt=head[u];
head[u]=tot;
} void work(int x){
f[x][]=a[x];
int s=0x3f3f3f,p=;
for(int i=head[x];i!=-;i=e[i].nxt){
int v=e[i].v;
if(vis[v]==)continue;
vis[v]=;
work(v);
f[x][]+=min(f[v][],f[v][]);
if(f[v][]<f[v][]){
f[x][]+=f[v][],p=;
}else{
f[x][]+=f[v][],s=min(s,f[v][]-f[v][]);
}
f[x][]+=min(f[v][],f[v][]);
}
if(p==)f[x][]+=s;
} int main(){
memset(head,-,sizeof(head));
scanf("%d",&n);
for(int i=;i<=n;i++){
int num,val,sum;
scanf("%d%d%d",&num,&val,&sum);
a[num]=val;
for(int j=;j<=sum;j++){
int b;
scanf("%d",&b);
adde(num,b);adde(b,num);
}
}
vis[]=;work();
printf("%d",min(f[][],f[][]));
}

多叉树转二叉树

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#define maxn 3005
using namespace std; int n,m,a[maxn],root;
int f[maxn][],vis[maxn];
int lson[maxn],rson[maxn],fa[maxn]; void work(int x)
{
f[x][]=a[x];
int s=0x3f3f3f,p=;
for(int i=lson[x];i!=;i=rson[i]){
work(i);
if(f[i][]<f[i][]){
f[x][]+=f[i][];s=min(f[i][]-f[i][],s);
}else f[x][]+=f[i][],p=;
f[x][]+=min(f[i][],f[i][]);
f[x][]+=min(f[i][],f[i][]);
}
if(p==)f[x][]+=s;
} int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++){
int num,val,q;
scanf("%d%d%d",&num,&val,&q);
a[num]=val;
for(int j=;j<=q;j++){
int s,now=lson[num];
scanf("%d",&s);
fa[s]=num;
if(j==)lson[num]=s;
else {
while(rson[now]!=){
now=rson[now];
}
rson[now]=s;
}
}
}
for(int i=;i<=n;i++)
if(fa[i]==)work(i),root=i;
printf("%d",min(f[root][],f[root][]));
}

提醒一点,多叉树转二叉树需要在执行dp之前跑个O(n)找到根节点

[vijos1144]小胖守皇宫<树形dp>的更多相关文章

  1. 【树形dp】vijos1144小胖守皇宫

    细节很精妙 描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步 ...

  2. Vijos1144小胖守皇宫【树形DP】

    皇宫看守 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫.皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看 ...

  3. Vijos 1144 小胖守皇宫 【树形DP】

    小胖守皇宫 描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步 ...

  4. 树形dp 之 小胖守皇宫

    题目描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:有边相连的宫殿间可以互相望见.大内保卫森严,三步一岗,五步一 ...

  5. 小胖守皇宫(VIJOS P1144 )题解

    题目描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每 ...

  6. vijos 小胖守皇宫

    点击打开题目 树形DP 显然会想到某个点放或不放守卫来定义状态,但在不放的情况下,需要分类讨论是父亲放还是一个儿子放,于是定义以下状态: f[root][0]表示自己不放,父亲也不放 f[root][ ...

  7. 【vijos1144】小胖守皇宫(树形DP)

    描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫 ...

  8. vijos1144(小胖守皇宫)

    也是ural1039 描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步 ...

  9. 树形DP 复习

    树形DP 树形DP:建立在树上的动态规划 一般有两种传递方式:根→叶或叶→根 前者出现在换根DP中,一般操作是求出某一个点的最优解,再通过这一个点推知其他点的最优解. 后者是树形DP的常见形式,一般树 ...

随机推荐

  1. 使用 EOLINKER 进行接口测试的最佳路径 (上)

    本文内容: 测试脚本管理:讲述如何在 EOLINKER 上设计测试项目目录结构. 编写测试脚本:讲述如何在 EOLINKER 上编写接口测试脚本. 测试脚本执行及报告:讲述如何在 EOLINKER 上 ...

  2. PHPRAP 1.0.2 发布,修复安装失败 Bug 和优化细节

    PHPRAP,是一个PHP轻量级开源API接口文档管理系统,致力于减少前后端沟通成本,提高团队协作开发效率,打造PHP版的RAP. 更新记录 [修复]修复在MySQL5.5版本下安装数据初始化sql文 ...

  3. 前端性能优化之Lazyload

    前端性能优化之Lazyload @(Mob前端-冬晨)[JavaScript|技术分享|懒加载] [TOC] Lazyload 简介 前端工作中,界面和效果正在变得越来越狂拽炫酷,与此同时性能也是不得 ...

  4. Java 八种基本类型和基本类型封装类

    1.首先,八种基本数据类型分别是:int.short.float.double.long.boolean.byte.char:   它们的封装类分别是:Integer.Short.Float.Doub ...

  5. ts文件的编译和运行

    hello.ts代码 function sayHello(person: string): string { return 'Hello, ' + person; } let user = 'Tom' ...

  6. Redis系列三 - 缓存雪崩、击穿、穿透

    前言 从学校出来,做开发工作也有一定时间了,最近有想系统地进一步深入学习,但发现基础知识不够扎实,故此来回顾基础知识,进一步巩固.加深印象. 最初开始接触编程时,总是自己跌跌撞撞.不断摸索地去学习,再 ...

  7. React初级坑

    1.使用vscode时,JSX语言会受beauty插件的影响,将标签换行了,如下: 解决办法:将编辑器右下角的语言由javascript改为javascript react就行了.

  8. [红日安全]Web安全Day12 – 会话安全实战攻防

    本文由红日安全成员: ruanruan 编写,如有不当,还望斧正. 大家好,我们是红日安全-Web安全攻防小组.此项目是关于Web安全的系列文章分享,还包含一个HTB靶场供大家练习,我们给这个项目起了 ...

  9. Jquery 系列化表单

    大家知道Jquery中有serialize方法,可以将表单序列化为一个“&”连接的字符串,但却没有提供序列化为Json的方法.不过,我们可以写一个插件实现. 我在网上看到有人用替换的方法,先用 ...

  10. JavaScript初学者

    学习如逆水行舟,不进则退.要逆流而上,逆战! 学习JavaScript这门语言,作为一个初学者,最重要的就是扎实的基础. 只要有了扎实的功底,在后期的学习中才能来去自如的应对各种逻辑难题 下面我们就来 ...