[51nod] 1378 夹克老爷的愤怒 #树形DP

1378 夹克老爷的愤怒

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租。

夹克老爷很愤怒,他决定派家丁常驻村中进行镇压。

诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来。

家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄。

夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?

Input

第1行:2个数N, K中间用空格分隔(1<= N <= 100000, 0 <= K <= N)。
之后N-1行:每行2个数S, E中间用空格分隔,表示编号为S的村庄同编号为E的村庄之间有道路相连。(0 <= S, E < N)。

Output

输出一个数说明要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?

Input示例

4 1
0 1
0 2
0 3

Output示例

1

Analysis分析

 Emmmm 显然树形DP

 那么我们记录状态为 DP[ u ][ 1/0 ],u为当前点,DP[ u ][ 1 ] 表示完全覆盖 u 以及 u 的子树,DP[ u ][ 0 ] 表示完美覆盖 u 以及 u 的子树

 完美覆盖是指:所有的家丁的管辖范围都没有重叠,最大效率的利用家丁进行镇压,哪怕是没有覆盖所有点也不能有所重叠

 完全覆盖是指所有点都被覆盖,哪怕出现重叠

 其实唯一可能有的区别就是 u 这个点有没有家丁(= =当然有的时候这两个状态是一样的:如果当前点必须放置家丁的话)

 现在来确定怎么放最好

 对于一条链,显然在离端点距离为 k 的那个点放下去是最优的

 那么对于一个树上的点,如果其子树未控制的点的深度和他相差 ≥k 的话,这个点必须要放置家丁:他的父节点是没有办法控制那个最深的未控制点的

 这是必须的情况,那么还有不必须的情况:该节点其中一个儿子支系中有家丁可以控制很远的距离,以至于可以通过 u 控制到其他子节点

 这种情况就需要计算了:如果那个家丁可以控制到所有子节点中最深的未控制点,那么当前这个点就没必要设家丁了

 但是如果不行, u 必须设置。具体的判别式见代码

 我相信我的代码可读性非常好因此我就不画图了(其实是时间紧懒得画 笑)

 那么我们对于每个点就需要设置四个参数:完美覆盖最小代价,完全覆盖最小代价,u及u的子树中所能控制到的最浅的深度(buoy),u及u的子树中未控制的最深的深度(anch)

 然后就嘿嘿嘿嘿

Code代码

 1 #include<stdio.h>
 2 #include<iostream>
 3 #define maxn 1000000
 4 using namespace std;
 5
 6 int DP[maxn][5],buoy[maxn],anch[maxn],depth[maxn],sz[maxn],n,k;
 7
 8 struct edge{
 9     int from,v;
10 }e[maxn*2]; int tot,first[maxn];
11 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; }
12
13 void dfs(int u,int pre){
14     int sum = 0; sz[u] = 1;
15     DP[u][0] = DP[u][1] = 0; buoy[u] = 1e9; anch[u] = -1e9;
16     for(int i = first[u];i;i = e[i].from){
17         int v = e[i].v; if(v == pre) continue;
18         depth[v] = depth[u]+1;
19         dfs(v,u);
20         sz[u] += sz[v];
21         buoy[u] = min(buoy[u],buoy[v]);
22         anch[u] = max(anch[u],anch[v]);
23         sum += DP[v][0];
24     }
25
26     if(sz[u] == 1){
27         DP[u][1] = 1;
28         DP[u][0] = 0;
29         if(!k) DP[u][0] = 1;
30         buoy[u] = anch[u] = depth[u];
31         return;
32     }
33
34 //    printf("#%d: buoy%d anch%d\n",u,buoy[u],anch[u]);
35     if(anch[u]-depth[u] >= k){ // Must set
36 //        printf("#%d: Poi A\n",u);
37         DP[u][0] = DP[u][1] = sum+1;
38         buoy[u] = depth[u]-k;
39         anch[u] = buoy[u]-1;
40     }else if(2*depth[u]-buoy[u] < anch[u]){ // Can choose
41 //        printf("#%d: Poi B\n",u);
42         DP[u][0] = sum;
43         DP[u][1] = sum+1;
44     }else{ // Needn‘t
45 //        printf("#%d: Poi C\n",u);
46         DP[u][0] = DP[u][1] = sum;
47         anch[u] = buoy[u]-1;
48     }
49 }
50
51 int main(){
52     scanf("%d%d",&n,&k);
53
54     for(int i = 1;i < n;i++){
55         int u,v; scanf("%d%d",&u,&v);
56         u++,v++; insert(u,v); insert(v,u);
57     }depth[1] = 1;
58
59     dfs(1,1);
60
61     printf("%d\n",DP[1][1]);
62
63 //    for(int i = 1;i <= n;i++){
64 //        printf("#%d: 0:%d 1:%d buoy:%d anch:%d\n",i,DP[i][0],DP[i][1],buoy[i],anch[i]);
65 //    }
66
67     return 0;
68 }

注释代码没删

时间: 2024-11-08 12:20:59

[51nod] 1378 夹克老爷的愤怒 #树形DP的相关文章

51nod 1378 夹克老爷的愤怒(树形DP+贪心)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 大致题意: 一棵1e5节点的树,安放某些位置,一个位置可以控制距他的距离不超过K的所有节点, 输入树和K,求控制全图(所有节点)需要安放最少的个数 思路: 假如是线性结构,一定是从边界开始每距离2k安放一个,然后最后正好或者再放置一个,这个贪心思路所有人都会. 当是树形结构时,仍然用那个贪心,显然安放的位置越靠近根节点控制的其他节点数越多,所以这里必须从

51nod 1378 夹克老爷的愤怒(树型dp+贪心)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 题意: 思路:要想放得少,尽量放在叶子节点处,叶子节点处点比较多. 从叶子节点开始往上回溯,到第k个点时就放置一名家丁,用dp[x]来记录状态,若为负,则表示该节点及其子树所需要家丁的最远距离,若为正,则表示该节点及其子树中家丁还能镇压的最大距离. 1 #include<cstdio> 2 #include<cstring> 3 #include&l

51Nod 1378 夹克老爷的愤怒

Description 一棵树,可以进行染色,被染色的点可以控制与它距离不超过 \(k\) 的所有点,问控制整棵树最少需要染几个点. Sol 贪心. 记录一下最深的未染色点和最浅的染色点,判断一下能否在子树中就完成,不能的话就把权值赋成最深未染色点深度+1,能的话就赋成染色点深度+1. 需要特判一下根. Code #include<cstdio> #include<vector> #include<ctime> #include<cstdlib> #incl

51nod 1380 夹克老爷的逢三抽一 堆 脑洞题

51nod 1380 夹克老爷的逢三抽一堆 脑洞题 题意 n个人围成一圈 然后每次可以选一个人,得到他的分数,然后他与他相邻的两个人出圈 总共选 n/3次, 保证n是3的倍数 题解 这道怎么说呢,应该比较巧妙吧,你开一个优先队列,大根堆,每次选择优先队列中最大的数,然后把他左右两个数删掉,比如 A B C 删掉 B ,那么就把 A+C-B 加入优先队列中,这其实就是相当于提供了一个后悔的机会,就像网络流中的反向边,如果在选中这个点的话,就相当于 B+(A+C-B) 然后就相当于 B 这个点 不选

51Nod 1380 夹克老爷的逢三抽一

Description 一开始有一个环,可以选择删除一个元素获得他的权值,同时删除与它相邻的两个元素,其他元素重新形成环,问能获得的最大价值. Sol 堆+贪心. 一开始从堆中加入所有元素,然后取出一个元素之后,加入他两边的元素之和-该位置的权值,并把左右两点删除. 一直到取出 \(\frac {n} {3}\) 个元素即可,左右元素可以用链表维护. 这样取出一个元素了以后可以进行反悔的操作,获得另外两个权值. xyx大爷说只要不相邻那么元素个数使得他必然有一种合法的删除方案. Code #in

树形DP+(分组背包||二叉树,一般树,森林之间的转换)codevs 1378 选课

codevs 1378 选课 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得相应的学分. 在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在

【树形dp】Bzoj3391 [Usaco2004 Dec]Tree Cutting网络破坏

Description 约翰意识到贝茜建设网络花费了他巨额的经费,就把她解雇了.贝茜很愤怒,打算狠狠报 复.她打算破坏刚建成的约翰的网络.    约翰的网络是树形的,连接着N(1≤N≤10000)个牛棚.她打算切断某一个牛棚的电源,使和这个牛棚相连的所有电缆全部中断.之后,就会存在若干子网络.为保证破坏够大,每一个子网的牛棚数不得超过总牛棚数的一半,那哪些牛棚值得破坏呢? Solution 树形dp裸题,刷水好欢乐. Code 1 #include<cstdio> 2 const int ma

POJ 3398 / UVA 1218 Perfect Service 树形DP

树形DP Perfect Service Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1378   Accepted: 668 Description A network is composed of N computers connected by N ? 1 communication links such that any two computers can be communicated via a uniqu

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节