
「HDU-2196」Computer (树形DP、树的直径)
发布日期:2021-05-09 00:11:57
浏览次数:13
分类:博客文章
本文共 2184 字,大约阅读时间需要 7 分钟。
树形dp,树的最长路径(最远点对)
题意
给出一棵nn个结点的无根树,求出每个结点所能到达的最远点的距离。
解法
将无根树转成有根树,并进行两次DFS。
第一次DFS求出每个结点在其子树中的正向最大距离和正向次大距离,记为
dp[0][x]
和dp[1][x]
,并标记最长距离所对应的子结点id[i]
,利用id[i]能跳过最大点计算第二大的点;此时可知对于每个结点ii,最远点的距离只有两种可能:
- 结点\(i\)的正向最大距离
- 结点\(i\)链接其父结点所能到达的最大距离,即反向最大距离
第二次DFS求出反向最长距离
- 由上步我们获得了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图可以知道我们建立的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点连接它的父节点所能到达的最大距离。(即前者往下走,后者先往上走之后很可能也往下走)
- 所以我们只要求出*反向最大距离*dist[i][2](即i节点往它的父节点走所能到达的最大距离)就可以知道i节点在整个树中能走的最大距离了。
- dist[i][2]求法:i节点往它的父节j点走,如果它的父节点的正向最大距离不经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j].
- 如果它的父节点的正向最大距离经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向次大距离+ W[i][j].
#includeusing namespace std;const int N = 1e4 + 100;int n, dp[3][N], id[N];vector p[N], val[N];void dfs1(int x,int f) {//第一个dfs更新子树的最大跟次大和s for (int i = 0; i < p[x].size(); i++){ int to = p[x][i]; if (to == f) continue; dfs1(to, x); if (dp[0][x] < dp[0][to] + val[x][i]) //这里是更新最大和,记住经过哪个儿子最大 { dp[0][x] = dp[0][to] + val[x][i]; id[x] = to; } } for (int i = 0; i < p[x].size(); i++){ int to = p[x][i]; if (to == f) continue; if (id[x] == to) continue; //跳过这个儿子,再剩下点里面找一个最大的,就是这个点次大的 dp[1][x] = max(dp[1][x], dp[0][to] + val[x][i]); }}void dfs2(int x,int f) {//这个是更新先往父亲节点走一步的最大和 for (int i = 0; i < p[x].size(); i++){ int to = p[x][i]; if (to == f) continue; if (to == id[x]) //难点,每个父亲都有两种方式,一个是再往父亲走一步,一个是走父亲的子树,max(dp[2][x], dp[1][x]),这个就体现出这两部了,注意经不经过这个点直接走子树最大和的那个点 dp[2][to] = max(dp[2][x], dp[1][x]) + val[x][i]; //这个是针对儿子,所以是dp[2][to] = ,体现了先走一步父亲,经过就走次大的,再走最大的就重复了一段 else dp[2][to] = max(dp[2][x], dp[0][x]) + val[x][i]; dfs2(to, x); //因为dfs1更新了所有子树的特点,子树的信息可以直接用了,父节点的信息从一步步dfs下去都已经更新好了,上面的也是可以直接用,每一步都看看是不是走父亲的父亲更好,一直更新最优 }}int main() { //freopen("in.txt", "r", stdin); ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0); while (cin >> n) { memset(dp, 0, sizeof dp); for (int i = 0; i <= n; ++i)val[i].clear(), p[i].clear(); for (int i = 2; i <= n; ++i) { int a, b; cin >> a >> b; p[i].push_back(a); val[i].push_back(b); p[a].push_back(i); val[a].push_back(b); } dfs1(1, -1); dfs2(1, -1); for (int i = 1; i <= n; ++i) cout << max(dp[0][i], dp[2][i]) << endl; }}
发表评论
最新留言
表示我来过!
[***.240.166.169]2025年04月01日 19时16分44秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
比技术还重要的事
2019-03-06
linux线程调度策略
2019-03-06
软中断和实时性
2019-03-06
Linux探测工具BCC(可观测性)
2019-03-06
Opentelemetry Metrics SDK
2019-03-06
流量控制--2.传统的流量控制元素
2019-03-06
SNMP介绍及使用,超有用,建议收藏!
2019-03-06
SDUT2161:Simple Game(NIM博弈+巴什博弈)
2019-03-06
51nod 1596 搬货物(二进制处理)
2019-03-06
来自星星的祝福(容斥+排列组合)
2019-03-06
Hmz 的女装(递推)
2019-03-06
HDU5589:Tree(莫队+01字典树)
2019-03-06
不停机替换线上代码? 你没听错,Arthas它能做到
2019-03-06
sharding-jdbc 分库分表的 4种分片策略,还蛮简单的
2019-03-06
分库分表的 9种分布式主键ID 生成方案,挺全乎的
2019-03-06
MySQL不会丢失数据的秘密,就藏在它的 7种日志里
2019-03-06
Python开发之序列化与反序列化:pickle、json模块使用详解
2019-03-06
回顾-生成 vs 判别模型-和图
2019-03-06
采坑 - 字符串的 "" 与 pd.isnull()
2019-03-06