膜拜了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>