http://acm.hdu.edu.cn/showproblem.php?pid=5834

题意:

一棵树上每个节点有一个价值$Vi$,每个节点只能获得一次,每走一次一条边要花费$Ci$,问从各个节点出发最多能收获多少价值。

思路:

需要考虑子节点和父亲节点两个方面。既然是这样,那就需要两次dfs来解决问题了,$dp[u][0]$表示从u出发最后还是回到u的最大价值和,$dp[u][1]$表示从u出发最后不回到u的最大价值和。

第一次dfs很显然就是计算出每个节点往其子树方向的$dp[u][0]$和$dp[u][1]$值。

第二次dfs就是再去考虑每个节点加上其父节点的情况,这里就需要维护一个最大值和一个次大值了,为什么呢?因为父节点的最大值可能最后停在了v子树,那么v子树到时候再去考虑父节点的时候就不对了,所以此时要将它改成次大值,这样它的最大值最后不会停在v子树。

总而言之,这是一道很经典的树形dp,不过没写出来。。

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+; int n;
int val[maxn];
int dp[maxn][];
vector<pll> G[maxn]; void dfs1(int u, int fa) //求出每个顶点往子树方向的最大值,dp[u][0]表示最终回到u,dp[u][1]表示最终不回到u
{
dp[u][]=dp[u][]=val[u];
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
dfs1(v,u);
if(dp[v][]-*w>) dp[u][]+=dp[v][]-*w;
}
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
int tmp = dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
if(dp[u][]<tmp) dp[u][]=tmp;
}
} void dfs2(int u, int fa, int cost) //处理往父亲节点的方向
{
int dir_tree=u;
if(fa!=-) if(dp[fa][]-*cost>) dp[u][]+=dp[fa][]-*cost;
int sub_large=dp[u][]=dp[u][];
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
int tmp=dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
if(tmp>=dp[u][]) //计算最大权值和次大权值
{
sub_large=dp[u][];
dp[u][]=tmp;
dir_tree=v;
}
else if(tmp>=sub_large) sub_large=tmp;
}
int pre0=dp[u][],pre1=dp[u][]; //出去该父节点对其子节点的影响
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
int tmp=dp[v][]-*w;
if(tmp>) dp[u][]-=tmp; //子节点v往父节点走时,肯定不会再算v节点的子树
if(dir_tree==v) dp[u][]=sub_large; //如果u的最大值最后停留在v子树,则改成次大值
if(tmp>) dp[u][]-=tmp; //和上面的第2句相同
dfs2(v,u,w);
dp[u][]=pre0,dp[u][]=pre1;
} } int main()
{
//freopen("in.txt","r",stdin);
int T;
int kase=;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) {G[i].clear();scanf("%d",&val[i]);}
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
printf("Case #%d:\n",++kase);
dfs1(,-);
dfs2(,-,);
for(int i=;i<=n;i++) printf("%d\n",dp[i][]);
}
return ;
}

HDU 5834 Magic boy Bi Luo with his excited tree(树形dp)的更多相关文章

  1. hdu 5834 Magic boy Bi Luo with his excited tree 树形dp+转移

    Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 13107 ...

  2. hdu-5834 Magic boy Bi Luo with his excited tree(树形dp)

    题目链接: Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: ...

  3. 【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边 ...

  4. 动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8UAAAJbCAIAAABCS6G8AAAgAElEQVR4nOy9fXQcxZ0uXH/hc8i5N+

  5. HDU 5834 Magic boy Bi Luo with his excited tree

    树形dp. 先dfs一次处理子树上的最优解,记录一下回到这个点和不回到这个点的最优解. 然后从上到下可以推出所有答案.细节较多,很容易写错. #pragma comment(linker, " ...

  6. HDU5834 Magic boy Bi Luo with his excited tree (树形DP)

    题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从i ...

  7. HDU5834Magic boy Bi Luo with his excited tree 树形dp

    分析:典型的两遍dfs树形dp,先统计到子树的,再统计从祖先来的,dp[i][0]代表从从子树回来的最大值,dp[i][1]代表不回来,id[i]记录从i开始到哪不回来 吐槽:赛场上想到了状态,但是不 ...

  8. 2016中国大学生程序设计竞赛 - 网络选拔赛 C. Magic boy Bi Luo with his excited tree

    Magic boy Bi Luo with his excited tree Problem Description Bi Luo is a magic boy, he also has a migi ...

  9. 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

    // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...

随机推荐

  1. 随机模拟MCMC和Gibbs Sampling

    随机模拟 统计模拟中有一个重要的问题就是给定一个概率分布 p(x),我们如何在计算机中生成它的样本.一般而言均匀分布 Uniform(0,1)的样本是相对容易生成的. 通过线性同余发生器可以生成伪随机 ...

  2. soapUI-Properties

    1.1.1  Properties 1.1.1.1 概述 - Properties Option Description   Toolbar 属性TestStep工具栏   Properties Li ...

  3. 在Keras模型中one-hot编码,Embedding层,使用预训练的词向量/处理图片

    最近看了吴恩达老师的深度学习课程,又看了python深度学习这本书,对深度学习有了大概的了解,但是在实战的时候, 还是会有一些细枝末节没有完全弄懂,这篇文章就用来总结一下用keras实现深度学习算法的 ...

  4. Qt元对象系统简介

    在Qt中提供了c++的扩展,提供了一种元对象系统的机制,(meta-object-system)的机制.其中包含了信号与槽的内部机制,能够访问到QObject子类的元对象信息的功能. Q_OBJECT ...

  5. http协议基础(四)http状态码

    一:http状态码 表示客户端http请求的返回结果.标记服务器端的处理是否正常.通知出现的错误等工作 状态码的类别如下: http状态码种类繁多,大概有60多种,实际上经常使用的只有14种,下面为一 ...

  6. 前端开发必备之Chrome开发者工具(上篇)

    本文介绍的 Chrome 开发者工具基于 Chrome 65版本,如果你的 Chrome 开发者工具没有下文提到的那些内容,请检查下 Chrome 的版本 简介 Chrome 开发者工具是一套内置于 ...

  7. uva11107 后缀数组

    题意给了n个串 然后计算 这些串中的子串在大于1/2的串中出现 求出这个串的最长长度. 将这些串用一个每出现的不同的字符拼起来 ,然后二分找lcp #include <iostream> ...

  8. hdu 6201 transaction transaction transaction

    https://vjudge.net/contest/184514#problem/H 题意: 一个商人为了赚钱,在城市之间倒卖商品.有n个城市,每个城市之间有且只有一条无向边连通.给出n个城市的货物 ...

  9. Python 为什么要用yield

    可能听说过,带有 yield 的函数在 Python 中被称之为 generator(生成器),何谓 generator ?我们先抛开 generator,以一个常见的编程题目来展示 yield 的概 ...

  10. Java SE 基础知识(String,Array)

    String 类: 1. 对于String对象的相等性判断来说,请使用equals()方法,而不是==.String的equals()是判断当前字符串与传进来的字符串的内容是否一致. 2. Strin ...