「HDU-2196」Computer (树形DP)

「HDU-2196」Computer
树形dp,树的最长路径(最远点对)

题意

给出一棵$n$个结点的无根树,求出每个结点所能到达的最远点的距离。

解法

将无根树转成有根树,并进行两次DFS。

  1. 第一次DFS求出每个结点在其子树中的正向最大距离正向次大距离,记为longest[i]secondary[i],并标记最长距离所对应的子结点mark[i]

    此时可知对于每个结点$i$,最远点的距离只有两种可能:

    • 结点$i$的正向最大距离
    • 结点$i$链接其父结点所能到达的最大距离,即反向最大距离
  2. 第二次DFS求出反向最长距离top[i]

    • 若其父节点的正向最大距离不经过$i$,反向最大距离为父节点的正向最大距离/反向最大距离+连接边

      $$top[i]=max(top[fa],longest[fa])+edge[fa][i]$$

    • 否则,反向最大距离为父节点的正向次大距离/反向最大距离+连接边

      $$top[i]=max(top[fa],secondary[fa])+edge[fa][i]$$

最终所求每个点的最大距离$ans[i]=max(longest[i],top[i])$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=1e4+10;

int head[maxn],tot,longest[maxn],secondary[maxn],top[maxn],mark[maxn];

struct node
{
int to,nex,v;
node(){}
node(int a,int b,int c):to(a),nex(b),v(c){}
}edge[2*maxn];

void add(int u,int v,int w)
{
edge[tot]=node(v,head[u],w);
head[u]=tot++;
edge[tot]=node(u,head[v],w);
head[v]=tot++;
}

void dfs(int u,int fa)
{
longest[u]=secondary[u]=0;
mark[u]=-1;
for(int k=head[u];k!=-1;k=edge[k].nex)
{
int v=edge[k].to;
if(v==fa) continue;
dfs(v,u);
if(longest[u]<=longest[v]+edge[k].v)
{
secondary[u]=longest[u];
longest[u]=longest[v]+edge[k].v;
mark[u]=v;
}
if(secondary[u]<=longest[v]+edge[k].v&&mark[u]!=v)
secondary[u]=longest[v]+edge[k].v;
}
}

void dfs1(int u,int fa)
{
for(int k=head[u];k!=-1;k=edge[k].nex)
{
int v=edge[k].to;
if(v==fa) continue;
if(mark[u]!=v)
top[v]=max(longest[u],top[u])+edge[k].v;
else
top[v]=max(secondary[u],top[u])+edge[k].v;
dfs1(v,u);
}
}

int main()
{
int N;
while(scanf("%d",&N)!=EOF)
{
int v,w;
tot=0;
memset(head,-1,sizeof(head));
for(int u=2;u<=N;u++)
{
scanf("%d%d",&v,&w);
add(u,v,w);
}
dfs(1,0);
memset(top,0,sizeof(top));
dfs1(1,0);
top[1]=secondary[1];
for(int i=1;i<=N;i++)
printf("%d\n",max(top[i],longest[i]));
}
return 0;
}