标签:最大和 span std 节点 ack scan name int lse
题意:给定n个点,保证是一棵树,输出每一个点到其他点的最大距离。
首先,该题目是DP思想。
那么我们先来想对于一个点,离它距离最大的点有两种情况,一种是在它的子树里面,另一种是通过它的父节点过来。
所以我们假设dp[ i ][ 0 ]表示一个点到其子树上某个点的最大距离,dp[ i ] [ 1 ]表示次大距离(一会会说次大距离有啥用)。
那么一种情况就解决了,那么如何解决从父节点过来的情况?
我们先设dp[ i ] [ 2 ]是由 i 的父节点走过来的最长路。
我们可以想到由父节点往子节点递归,如果某个点距其最远的点是通过其父节点过来,那么相对其父节点,该店也是其父节点的最远点,行得通。
但是这个父节点的最远点又有两种情况,一种是那条最远路包含了该子节点,又或者是不包含该子节点。
第一种情况:对于包含的情况,我们不能走这条路,就要用到上面说的次大距离,也就是说假设 h 是 i 的父节点,
那么dp[ i ][ 2 ]在这种情况下等于父节点 ( h点 ) 的最大距离+ h点到 i 点的距离,而父节点的最大距离要在dp[ h ][ 1 ]和 dp[ h ] [ 2 ]中取,
因为相对于其某点来说我们只求出了子树中的最大和通过其父节点到该节点最大,要在两者中再取一个最大值才是最终的最大值。
而这种情况需要的是次大值不是最大值所以选取dp[ h ][ 1 ]而不是dp[ h ][ 2 ]。(如果这两行没明白可以结合下面第二种情况看一下)
即dp[ i ][ 2 ] =max( dp[ h ][ 1 ] ,dp[ h ] [ 2 ] ) + h to i的值。
第二种情况:不包含,则我们直接取到父节点的最大路加上父节点到该节点的路。
到其父节点的最大路如上所说要取dp[ h ][ 0 ]和dp[ h ][ 2 ]的最大值,即从父节点的父节点过来的最大路和父节点的子树上的最大路两者之中选个大的。
所以dp[ i ][ 2 ] =max( dp[ h ][ 0] ,dp[ h ] [ 2 ] ) + h to i的值。
判断父节点的最大路是否经过此路的方法也不用额外记录,只需要判断
dp[ i ][ 0 ] + h to i 是否和 dp[ h ] [ 0 ]相等即可。
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <map> #include <set> #include <string> using namespace std; struct node { int to; int val; }; vector<node> q[10005]; int dp[10005][4],n; void dfs1(int root) { int most=0,second=0; for(int i=0;i<q[root].size();i++) { node child=q[root][i]; dfs1(child.to); int cost=dp[child.to][0]+child.val; if(cost>=most) { second=most; most=cost; } else if(cost>second) second = cost; } dp[root][0]=most; dp[root][1]=second; } void dfs2(int root) { for(int i=0;i<q[root].size();i++) { node child=q[root][i]; if(dp[child.to][0]+child.val==dp[root][0]) dp[child.to][2]=max(dp[root][2],dp[root][1])+child.val; else dp[child.to][2]=max(dp[root][2],dp[root][0])+child.val; dfs2(child.to); } } int main() { while(~scanf("%d",&n)) { for(int i=2;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); node a;a.val = y; a.to=i; q[x].push_back(a); } memset(dp,0,sizeof dp); dfs1(1); dp[1][2]=0; dfs2(1); for(int i=1;i<=n;i++) printf("%d\n",max(dp[i][0],dp[i][2])); for(int i=1;i<=n;i++) q[i].clear(); } return 0; }
标签:最大和 span std 节点 ack scan name int lse
原文地址:https://www.cnblogs.com/fantastic123/p/8970265.html