题解——[HAOI2009]毛毛虫 树形DP

题意:

给你一棵树,从树中取出一部分满足:是一条链+一些直接连在这条链上的节点

求节点数最多的合法取出部分。

题解:

其实这题还是不难?

观察到对于任意一条链,

只有两种情况: 一条路走到底 or  以某个点为中转

f[x]表示从x往下走,一路走到底的包括x的最优解,

f[x]包括x也包括father[x](将会加入它的贡献)

观察到以某个点为中转的情况:

倘若某条链以一个点为中转,那么这条链将无法向上产生贡献,

若没有,则变为第一种情况,且一定可以向上产生贡献, 以点x为中转的所有链都可以通过各个儿子的搭配得到

因此f[x]可以直接从f[son]中选取最优的来得到,

然后用f[x]来更新ans,

再选取儿子中的前2大,搭配起来加上x组成链,更新ans

所以dfs一遍然后输出ans即可,复杂度O(n);

细节还是挺多的,要注意。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 350000
 5 #define ACway 700000
 6 #define getchar() *o++
 7 char READ[10001000],*o=READ;
 8 int n,m,ans;
 9 int in[AC],f[AC];
10 int date[ACway],Head[AC],Next[ACway],tot;
11 /*观察到对于任意一条链,只有两种情况:
12 一条路走到底 :以某个点为中转
13 f[i]表示从i往下走,一条路走到底的最优解(不包括i)(非最长链)
14 但这样并不方便。。。。因为要分的情况太多,
15 所以f[x]表示从x往下走,一路走到底的包括x的最优解,
16 f[x]包括x也包括father[x]
17 观察到以某个点为中转的情况:
18 倘若某条链以一个点为中转,那么这条链将无法向上产生贡献,
19 若没有,则变为第一种情况。且一定可以向上产生贡献,
20 以点x为中转的所有链都可以通过各个儿子的搭配得到,*/
21
22 inline int read()
23 {
24     int x=0;char c=getchar();
25     while(c > ‘9‘ || c < ‘0‘) c=getchar();
26     while(c >= ‘0‘ && c <= ‘9‘) x=x*10+c-‘0‘,c=getchar();
27     return x;
28 }
29
30 inline void upmax(int &a,int b)
31 {
32     if(b > a) a=b;
33 }
34
35 inline void add(int f,int w)
36 {
37     date[++tot]=w,Next[tot]=Head[f],Head[f]=tot;
38     date[++tot]=f,Next[tot]=Head[w],Head[w]=tot;
39     ++in[f],++in[w];
40 }
41
42 void pre()
43 {
44     int a,b;
45     n=read(),m=read();
46     for(R i=1;i<=m;i++)
47     {
48         a=read(),b=read();
49         add(a,b);
50     }
51 }
52
53 void dfs(int x,int fa)
54 {
55     int now,maxn=0,maxn2=0;
56     f[x]=1 + in[x];//因为包括了自己,所以至少也是1 + in[x]了
57     for(R i=Head[x] ; i ;i=Next[i])
58     {
59         now=date[i];
60         if(now == fa) continue;
61         dfs(now,x);
62         upmax(f[x],f[now] + in[x] - 1);//因为既要加自己,又要减儿子,抵消了,所以只用加in就可以了
63         if(f[now] > maxn)//但是由于f[now]会包括x,所以也要减掉,,,
64         {
65             maxn2=maxn;
66             maxn=f[now];
67         }
68         else upmax(maxn2,f[now]);
69     }
70     upmax(ans,f[x]);
71     upmax(ans,maxn + maxn2 + in[x] - 3);//同上,只不过多减一个儿子
72 }//因为也会包括x,所以会重复2次
73
74 void work()
75 {
76     dfs(1,0);//随便选个点做根节点吧
77     printf("%d\n",ans);
78 //    for(R i=1;i<=n;i++) printf("%d %d\n",i,f[i]);
79 }
80
81 int main()
82 {
83 //    freopen("in.in","r",stdin);
84     fread(READ,1,10000000,stdin);
85     pre();
86     work();
87 //    fclose(stdin);
88     return 0;
89 }

原文地址:https://www.cnblogs.com/ww3113306/p/9097545.html

时间: 2024-10-29 07:33:07

题解——[HAOI2009]毛毛虫 树形DP的相关文章

[haoi2009]毛毛虫 树形dp

这道题细节处理不少,但要AC不难: 设以i节点为根节点的子树能形成的最大的毛毛虫长度为f[i],则f[i]=max(f[j])+i节点的孩子数: 答案需要f最大和次大的两个子树合并,而且若合并的位置不是根节点,ans++: 我就是坑在了最后一点上,最后打表找到了问题: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=30

树的点分治 (poj 1741, 1655(树形dp))

poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子树的节点数. 再dfs  找出以某节点为根的最大子树,节点最少. 复杂度(n) /***Good Luck***/ #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cs

Strategic Game(树形DP)

目录 Strategic Game(树形DP) 题目 题意 思路 题解 Strategic Game(树形DP) 题目 Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad. Now he has the following problem. He must defend

题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换根法 作为一道不定根的树形DP,如果直接对每个点进行DP,可能时间会炸掉 但是,优秀的二次换根和扫描法可以再O(n^2)内解决问题. 二次扫描的含义:(来自lyd 算法竞赛进阶指南) 第一次扫描:任选一个节点为根节点(我会选1)在树上进行树形DP,在回溯时,从儿子节点向父节点(从底向上)进行状态转移

HDU-2196 Computer (树形DP)

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

选课 树形DP+多叉树转二叉树+dfs求解答案

问题 A: 选课 时间限制: 1 Sec  内存限制: 128 MB提交: 6  解决: 3[提交][状态][答疑][寄存][题解] 题目描述 大 学里实行学分.每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分.学生最后的学分是他选修的各门课的学分的总和. 每个学生都要选择规定数量的课程.其中有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如,<数据结 构>必须在选修了<高级语言程序设计>之后才能选修.我们称&l

Vijos p1770 大内密探 树形DP+计数

4天终于做出来了,没错我就是这么蒟蒻.教训还是很多的. 建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性. 大神题解传送门 by iwtwiioi 我的题解大家可以看注释"//"部分 本题我用的树形DP中dp[x][fa][need]表示编号为x的节点的父亲选(1)没选(0),x的父亲需(1)不需要(0)其他节点来覆盖. 若父亲节点选了,则need肯定为0,所以不存在fa==1而need==1的状态,相当于浪费了¼的空间.毕竟数据范围比较小,而且程序要有可读性!程

poj 4045 Power Station(初涉树形dp)

http://poj.org/problem?id=4045 大致题意:有n个村庄,求将发电站建在哪一个村庄使得花费最少.这是一个无向无环图.简化一下就是求一个节点使它到其他所有节点的距离和最小. 起初一直在向最短路上靠,但因为节点和边数太大,必定TLE.然后无比强大的啸神随便写了两个dfs就过掉了,简直膜拜.赛后搜了搜题解,发现这是道树形dp.sad,真的要好好刷dp了. 大体思路是将这个无向无环图看做一个树,我们就在这个树上进行动态规划.首先先随便拿一个节点看做根节点(假设节点1),计算出它

hdu5293 Tree chain problem 树形dp+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最大. 比赛的时候以为是树链剖分就果断没去想,事实上是没思路. 看了题解,原来是树形dp.话说多校第一场树形dp还真多. . .. 维护d[i],表示以i为根节点的子树的最优答案. sum[i]表示i的儿子节点(仅仅能是儿子节点)的d值和. 那么答案就是d[root]. 怎样更新d值 d[i] = max(sum[i] , w[p]+s