树形DP求树的直径
设D[x]表示从结点x出发,走向以x为根的子树,能够到达的最短距离,设x的子结点
y
1
,
y
2
.
.
.
y
t
y_1,y_2...y_t
y1,y2...yt,则有
D
[
x
]
=
m
a
x
(
D
i
+
e
d
g
e
(
x
,
y
i
)
)
i
=
1
,
2
,
.
.
.
t
D[x] = max ( D_i + edge(x, y_i) ) i = 1,2,...t
D[x]=max(Di+edge(x,yi))i=1,2,...t
定义F[x]为经过x的最长链的长度,对于x的任意两个结点
y
i
,
y
j
y_i,y_j
yi,yj,F[x]由四部分构成,从
y
i
y_i
yi到
y
i
y_i
yi子树的最远距离,边
(
x
,
y
i
)
(x, y_i)
(x,yi),边
(
x
,
y
j
)
(x, y_j)
(x,yj),
y
j
y_j
yj到
y
j
y_j
yj子树的最远距离。
code
void dp(int x)
{
v[x] = 1;
for(int i = head[x]; i; i = net[i])
{
int y = ver[i];
if(v[y])
continue;
dp(y);
ans = max(ans, d[x] + d[y] + edge[i]);
d[x] = max(d[x], d[y] + edge[i]);
}
}
例题
说明
此处给出的是每个结点的权值,并不是每条边的权值,但是求法与求树的直径差不多
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1E5+5;
vector<ll> vec[N];
ll n, a[N], dp[N], ans = -1E9;
void dfs(ll x, ll fa)
{
dp[x] = a[x];
for(ll i = 0; i < vec[x].size(); i++)
{
ll y = vec[x][i];
if(y == fa)
continue;
dfs(y, x);
ans = max(ans, dp[x] + dp[y]);
dp[x] = max(dp[x], dp[y] + a[x]);
}
ans = max(ans, dp[x]);
}
int main()
{
scanf("%lld", &n);
for(ll i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for(ll i = 1; i < n; i++)
{
ll u, v;
scanf("%lld%lld", &u, &v);
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs(1, 0);
cout << ans << endl;
return 0;
}