HDU - 2196 Computer(树形dp)
题目链接:点击查看
题目大意:给定n个点以及n-1条边,保证可以组成一棵树,问每个点所能到达的最远距离
题目分析:首先这是一颗无向图所组成的树,经过分析,我们可以得到任何一个点,对于它所能到达的最远距离取决于两个条件,一个是该点向下可以到达的最远距离,或者是该点向上可以到达的最远距离,求该点向下的距离好求,可以利用树形dp的一般形式,回溯法,直接自底向上地往上求,不仅需要维护一个最大值,还需要维护一个次大值,接下来会用到,然后就是怎么求向上可以达到的距离了,我们可以在写一个dfs,刚才那个是自底向上维护,那么新的dfs就变成自顶向下维护就好了,其实本质上就是交换了一下转移方程和递归入口的顺序。
那么接下来在分析一下转移方程该怎么写,刚才我们提到了一共需要维护三个值,即向下的最大值,向下的次大值和向上的最大值,故我们需要用三个数组来维护,我们就用dp[N][3]来维护,第一维分别表示每个点,第二维的0,1,2分别表示以上三个值。
关于最大值和次大值,只需要遵循
- 更新最大值前先更新次大值
- 更新不了最大值时检查是否可以更新次大值
这样就可以直接自底向上转移了,还剩一个向上的最大值,这个我们该怎么想呢
我先将转移方程放上然后在来解释:
dp[v][2]=max(dp[v][0]+w==dp[u][0]?dp[u][1]:dp[u][0],dp[u][2])+w;
其中v表示为u的儿子,w表示为u和v之间的权值
既然是自顶向下转移,那么转移的方向就是u->v来转移,dp[u][2]可以当做已知条件来用,我们可以直接用这个值加上u和v之间的权值w来更新dp[v][2],这样确实是其中的一种情况,但却不一定是最优解,所以我们需要经过比较选择出最优解来更新dp[v][2]才行,那么还有哪些途径可以更新它呢?我们假设当前的u为根节点,那么既然v位于u的子树中,我们需要判断v是否位于u向下最大值的子树中,如果是的话,那么经过v点向上,我们可以经过根节点u当做中转点,到达u点的另一个次大值的子树中,这样可以保证了距离最大,如果v不在u的向下最大值的子树中,那么必定可以经过u到达最大值的子树中,这样通过比较这三种情况来确定了更新dp[v][2]的状态。
最后输出的结果便是从dp[i][0]和dp[i][2]中选择较大的一个输出了。
上代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<sstream>
#include<cmath>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;struct Node
{int to,w;Node(int TO,int W){to=TO;w=W;}
};vector<Node>node[N];int dp[N][3];//0:向下最大值,1:向下次大值,2:向上最大值void dfs_down(int u,int fa)
{int mmax=0;//最大值int mx=0;//次大值for(int i=0;i<node[u].size();i++){int v=node[u][i].to;int w=node[u][i].w;if(v==fa)continue;dfs_down(v,u);int temp=dp[v][0]+w;if(temp>=mmax){mx=mmax;mmax=temp;}else if(temp>mx){mx=temp;}}dp[u][0]=mmax;dp[u][1]=mx;
}void dfs_up(int u,int fa)
{for(int i=0;i<node[u].size();i++){int v=node[u][i].to;int w=node[u][i].w;if(v==fa)continue;dp[v][2]=max(dp[v][0]+w==dp[u][0]?dp[u][1]:dp[u][0],dp[u][2])+w;dfs_up(v,u);}
}int main()
{
// freopen("input.txt","r",stdin);int n;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++)node[i].clear();for(int i=2;i<=n;i++){int w,u;scanf("%d%d",&u,&w);node[u].push_back(Node(i,w));node[i].push_back(Node(u,w));}memset(dp,0,sizeof(dp));dfs_down(1,-1);dfs_up(1,-1);for(int i=1;i<=n;i++)cout<<max(dp[i][0],dp[i][2])<<endl;}return 0;
}
HDU - 2196 Computer(树形dp)相关推荐
- HDU 2196 Computer 树形DP经典题
链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问 ...
- HDU - 2196(树形DP)
题目: A school bought the first computer some time ago(so this computer's id is 1). During the recent ...
- hdu 2196(经典树形dp)
题意:给你一颗边带权值的树,求树上的每一点距离其最远的一个点的距离 解题思路:这道题网上说是经典的树形dp,不过确实很巧妙.两次dfs应该是比较好想到的,因为某节点最大的距离要么就是一直走到叶子节点, ...
- HDU Starship Troopers (树形DP)
Starship Troopers Time Limit : 10000/5000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) ...
- HDU 5148 Cities (树形DP)*
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5148 #include<bits/stdc++.h> using namespace st ...
- HDU - 4705 Y(树形dp)
题目链接:点击查看 题目大意:给出一棵树,求三个点不在一条线上的个数 题目分析:正难取反,正着求不管是暴力还是有点技巧都是实现不了的,我们可以求出来三个点在一条直线上的方案数,然后用总的排列组合的方案 ...
- HDU - 5242 Game(树形dp+树链剖分/树上贪心+思维)
题目链接:点击查看 题目大意:给出一棵包含n个节点的树,每个节点都有一个权值,整棵树的根是点1,问从点1开始向下一直走到叶子节点,可以走k次,怎么样走权值和最大,每个节点被走过一次后权值会变为0 题目 ...
- Problem F. Grab The Tree HDU - 6324(树形dp+博弈)
Little Q and Little T are playing a game on a tree. There are nn vertices on the tree, labeled by 1, ...
- HDU 4616 Game 树形DP
Problem Description Nowadays, there are more and more challenge game on TV such as 'Girls, Rush Ahea ...
最新文章
- 在hadoop上运行python_hadoop上运行python程序
- IT圈,他的牙如此不同
- synchronized关键字实现原理
- 第三次学JAVA再学不好就吃翔(part108)--带缓冲的字符流
- windows相关知识点分析
- 中班机器人上课视频_家委会:出班费买智能扫地机器人,不用家长搞卫生了,莫名其妙...
- OpenCV学习笔记(三):图像对比度、亮度调整源码
- 为什么有些女孩在发现渣男的真面目以后,还喜欢他们?
- 【计算机组成原理】指令格式
- asp.net用url重写URLReWriter实现任意二级域名(续)
- 基于JAVA+SpringMVC+Mybatis+MYSQL的教学管理平台
- remmima 不能保存_不再使用RememBear密码管理器忘记密码
- 用gambit学博弈论--完全信息动态博弈-博弈扩展式、博弈树(二)
- 《鹰猎长空》讲述戏曲与电影的渊源
- (二)PUN 2基本教程
- 阿里云盘PC端内测版可以下载安装了 还送你800G扩容福利码!
- Qt开发之QLineEdit简单介绍
- multimap的实际用途
- 猪哥学习群直播第一期:人工智能在银行电信企业中的应用
- 【北京.5月28日】第六届 Mobile Dev Day – WP7优秀应用经验分享日