题目:
题意:
给一棵边带权的树,求哪些点在至少一条直径上n<=200000
题解:
这里用dp比较方便,f[i]最长g[i]次长
这次从上到下,先算父亲再算孩子,h[i]表示i向除子树外最远距离
代码:
#include <cstdio>
#include <iostream>
#define N 200005
using namespace std;
int tot,nxt[N*2],point[N],v[N*2],ans[N],f[N],g[N],n,i,maxx,anss,h[N];
void addline(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void treedp(int x,int fa)
{
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
treedp(v[i],x);
if (f[v[i]]+1>f[x])
{
g[x]=f[x];
f[x]=f[v[i]]+1;
}
else g[x]=max(g[x],f[v[i]]+1);
}
maxx=max(maxx,f[x]+g[x]);
}
void dfs(int x,int fa)
{
int cnt=0;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa) if (f[x]==f[v[i]]+1) cnt++;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
if (f[x]!=f[v[i]]+1 || (f[x]==f[v[i]]+1 && cnt>1)) h[v[i]]=max(h[x],f[x])+1;
else h[v[i]]=max(h[x],g[x])+1;
dfs(v[i],x);
}
}
int main()
{
scanf("%d",&n);
for (i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);a++;b++;
addline(a,b);
}
treedp(1,0);
dfs(1,0);
for (i=1;i<=n;i++)
if (f[i]+max(g[i],h[i])==maxx) ans[++anss]=i;
for (i=1;i<=anss;i++) printf("%d\n",ans[i]-1);
}
树形DP求直径节点
本文介绍了一种使用动态规划解决树形结构中求直径问题的方法,并提供了完整的C++实现代码。通过两次DFS遍历,分别计算每个节点的最长路径和次长路径,最终找出处于树直径上的所有节点。
539

被折叠的 条评论
为什么被折叠?



