HDU 2196——Computer(树形DP)

膜拜了NN个大神的代码,看了一整天,弱菜伤不起啊。求拜师啊

问题分析:求树上每个节点到其它节点的最远距离

每个节点到其它节点的最远距离就是以该节点为根的树所能达到的最大深度,这样子的话,要把每个节点转化为根,总共dfs的次数为节点数,肯定超时

于是~

一个节点的最长路:1.从该节点往下取得最长路(子树部分)  2.从该节点往上取得的最长路(父节点往上的部分)

情况1:自下而上的dfs(先深搜后操作)

情况2:自上而下的dfs(先操作后深搜){

如果节点u的子节点v在 以u为父亲的子树上的最长路,那么点v的最长路由u的父亲路和次长路中的max取得

否则 点v的最长路由u的父亲路和最长路中的max取得

}

(画颗树就可以非常清楚了)

贴上自己的代码~~~

^。^

<span style="font-size:18px;">/*dp[i][0] 表示以i为父亲的子树中的最大距离
dp[i][1] 表示以i为父亲的子树中的次大距离
dp[i][2] 表示i的父树的最大距离
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ms(s,i) memset(s,i,sizeof s)
#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)
#define lng long long
#define pb push_back
#define linf 100000
#define M 11000
#define fx(i,x,n) for(int i=x;i<n;++i)
using namespace std;
int dp[M][3],f[M],l[M],vis[M];
template<class T> T gcd(T a,T b){return b==0?a:gcd(b,a%b);}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
struct pp{int v,w,next;}edge[M*2];int tot,head[M],root,n,m;
inline void addedge(int u,int v,int w,int *h){edge[tot].v=v,edge[tot].w=w,edge[tot].next=h[u],h[u]=tot++;}//邻接表

void dfs1(int u)//自下而上,更新子树的最长路和次长路,先dfs后操作
{
    vis[u]=1;
    ffl(i,u){//引用邻接表
        int v=edge[i].v;//节点u的子节点
        if(vis[v]) continue;
        dfs1(v);
        if(dp[u][0]<dp[v][0]+edge[i].w){//最长的是所有子节点中的max
            dp[u][1]=dp[u][0];
            dp[u][0]=dp[v][0]+edge[i].w;
        }
        else if(dp[u][1]<dp[v][0]+edge[i].w){//次长的是所有子节点的second
            dp[u][1]=dp[v][0]+edge[i].w;
        }
    }
}
void dfs2(int u)
{
    vis[u]=1;
    ffl(i,u){//引用邻接表
        int v=edge[i].v;//节点u的子节点
        if(vis[v]) continue;
        if(dp[v][0]+edge[i].w==dp[u][0]){//节点v的最长路+边(u,v)的权值=节点u的最长路,那么节点v在节点u的最长路上
            dp[v][2]=max(dp[u][1],dp[u][2])+edge[i].w;//等于父亲路和次长路中的MAX
        }
        else
            dp[v][2]=max(dp[u][2],dp[u][0])+edge[i].w;//否则等于父亲路和最长路中的MAX
        dfs2(v);//自上而下
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        int u,w;
        tot=0,ms(head,-1);//记得初始化
        for(int i=2;i<=n;++i){
            scanf("%d%d",&u,&w);
            addedge(u,i,w,head);addedge(i,u,w,head);//邻接表构建无向图
        }
        ms(vis,0),ms(dp,0);
        dfs1(1);
        ms(vis,0);//重新初始化vis
        dfs2(1);
        for(int i=1;i<=n;++i){
            printf("%d\n",max(dp[i][0],dp[i][2]));//最长路和父亲路中的MAX
        }
    }
    return 0;
}
</span>
时间: 2024-08-18 22:07:56

HDU 2196——Computer(树形DP)的相关文章

HDU 2196 Computer 树形DP经典题

链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问每台电脑和其它电脑的最远距离是多少. 思路:这是一道树形DP的经典题目.须要两次DFS,第一次DFS找到树上全部的节点在不同子树中的最远距离和次远的距离(在递归中进行动态规划就可以),第二次DFS从根向下更新出终于答案.对于每次更新到的节点u,他的最远距离可能是来自u的子树,或者是u的父亲节点的最远

HDU 2196 Computer 树形DP 经典题

给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权,放在数组cost中 令tree(i)表示以节点i为根的子树 对于节点i,离该节点最远的点要不就是在tree(i)中,要不就是在father(i)上面 令: dp[i][1] : 在子树tree(i)中,离i最远的距离 dp[i][2] : 在子树tree(i)中,离i第二远的距离 (递推的时候需要)

HDU 2169 Computer[树形dp]

Computer 时限:1000ms Problem Description A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of s

HDU 2196(树形dp

题目:求出一棵树上的所有点到其他点的最长距离. 思路:取一个根节点进行dfs,先求出每个节点到子节点的最长路和次长路(也就是与最长路不同的最长的路,有可能与最长路长度相等),并记录最长路和次长路通过的相邻节点的标号.然后进行第二次dfs,考虑最长路是通过父节点的情况,如果该节点v在父节点的最长路上,那么需要取次长路,否则就取最长路. 第二次dfs的时候最长路的通过节点还是要更新,因为若某个父节点的最长路是朝祖先走的,那么其子节点的最长路一定朝祖先走,且与v是否在父节点向下的最长路上无关. #in

HDU 2196 Computer 经典树形DP

一开始看错题了,后来发现原来是在一颗带权的树上面求出距离每一个点的最长距离,做两次dfs就好,具体的看注释? #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #incl

hdu 1011(树形dp)

Mark.看着吴神博客写的,还未完全懂. 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string>

HDU 2196Computer(树形DP)

给你一颗边带权值的树,求树上的每一点距离其最远的一个点的距离 比较典型的题了,主要方法是进行两次DFS,第一次DFS求出每一个点距离它的子树的最远距离和次远距离,然后第二次DFS从父节点传过来另一侧的树上的距离它的最远距离进行一次比较便可得出任意点的最远距离了 之所以需要记录最远和次远是为了辨别父节点的最远距离是否是根据自己得来,如果是的话应该选择父节点的次远距离,保证结果的准确性 1 //#pragma comment(linker,"/STACK:102400000,102400000&qu

树形DP [HDU 2196] Computer

Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3526    Accepted Submission(s): 1788 Problem Description A school bought the first computer some time ago(so this computer's id is 1). D

HDU 2196 树状dp 求树中节点之间的最长距离

Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3749    Accepted Submission(s): 1892 Problem Description A school bought the first computer some time ago(so this computer's id is 1). Du

HDU-2196 Computer (树形DP)

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