5 1 1 2 1 3 1 1 1
3 2 3 4 4
求一个树中所有节点能到达的最远距离f[i]。要用两个dfs。
分析:
首先第一个dfs求出所有每个节点i在其子树中的正向最大距离和正向次大距离和dist[i][0]和dist[i][1](如果i节点在子树中最大距离经过了2号儿子,那么次大距离就是不经过2号儿子的最大距离)。并且还要标记longest[i]=j表示节点i在其子树中的最大距离经过了节点j(即j是i的一个儿子)。
由上步我们获得了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图可以知道我们建立的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点连接它的父节点所能到达的最大距离。(即前者往下走,后者先往上走之后很可能也往下走)
所以我们只要求出反向最大距离dist[i][2](即i节点往它的父节点走所能到达的最大距离)就可以知道i节点在整个树中能走的最大距离了。
dist[i][2]求法:i节点往它的父节j点走,如果它的父节点的正向最大距离不经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j].
如果它的父节点的正向最大距离经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向次大距离+ W[i][j].
上面就是dfs2要求的值。最终f[i] = max(dist[i][0],dist[i][2])
程序:
#include"stdio.h" #include"string.h" #include"iostream" #define M 100009 #define inf 99999999 #define eps 1e-9 #include"math.h" using namespace std; struct st { int u,v,w,next; }edge[M*3]; struct node { int max1,max2,maxj; }p[M]; int head[M],use[M],t,dis[M],in[M],longest[M]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].next=head[u]; head[u]=t++; } void dfs(int u)//求正向最大距离和正向次大距离 { use[u]=1; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!use[v]) { dfs(v); int MM=p[v].max1+edge[i].w; if(p[u].max1<MM) { longest[u]=v; int tt=p[u].max1; p[u].max1=MM; p[u].max2=tt; } else if(p[u].max2<MM) { p[u].max2=MM; } } } if(in[u]==1) p[u].max1=p[u].max2=0; } void DFS(int u,int fa)//求反向最大距离 { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(fa==v)continue; if(v==longest[u]) p[v].maxj=max(p[u].maxj,p[u].max2)+edge[i].w; else p[v].maxj=max(p[u].maxj,p[u].max1)+edge[i].w; DFS(v,u); } } int main() { int n,i,j,c; while(scanf("%d",&n)!=-1) { init(); memset(in,0,sizeof(in)); for(i=2;i<=n;i++) { scanf("%d%d",&j,&c); add(i,j,c); add(j,i,c); in[i]++; in[j]++; } memset(p,0,sizeof(p)); memset(use,0,sizeof(use)); for(i=1;i<=n;i++) { if(in[i]>1) { dfs(i); DFS(i,-1); break; } } for(i=1;i<=n;i++) { printf("%d\n",max(p[i].max1,p[i].maxj)); } } return 0; }