Date:2022.03.29
题意描述:
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。
输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。
输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。
数据范围
1≤n≤10000,
1≤ai,bi≤n,
1≤ci≤105
输入样例:
5
2 1 1
3 2 1
4 3 1
5 1 1
输出样例:
2
思路:对于一个结点uuu,与其距离最远的点可能有两种情况:
①在其下方:显然是向下走距离uuu的最远距离,记为down1[u]down1[u]down1[u]。
②在其上方:记为up[u],up[u],up[u],仍然分为两种情况。
(1)从它的父节点fa[u]fa[u]fa[u]再往上走:
此时up[u]=up[fa[u]]+g[u][fa[u]];up[u]=up[fa[u]]+g[u][fa[u]];up[u]=up[fa[u]]+g[u][fa[u]];
(2)从它的父节点fa[u]fa[u]fa[u]再往下走:由于是从uuu来的,因此不能走回uuu,此时仍然有两种情况:
a.fa[u]fa[u]fa[u]向下走时,down1[fa[u]]==down1[u]+g[fa[u]][u];down1[fa[u]]==down1[u]+g[fa[u]][u];down1[fa[u]]==down1[u]+g[fa[u]][u];【即fa[u]fa[u]fa[u]向下走的最长路径经过uuu】,由于不能再经过uuu,还要保证最长,因此选择次长路径down2[fa[u]]down2[fa[u]]down2[fa[u]]。
即此时:up[u]=max(up[u],down2[fa[u]]+w[i]);up[u]=max(up[u],down2[fa[u]]+w[i]);up[u]=max(up[u],down2[fa[u]]+w[i]);
b.否则选择最大路径down1[fa[u]]down1[fa[u]]down1[fa[u]]。
即此时:up[u]=max(up[u],down1[fa[u]]+w[i]]);up[u]=max(up[u],down1[fa[u]]+w[i]]);up[u]=max(up[u],down1[fa[u]]+w[i]]);
除此之外,先处理出所有down1[u]、down2[u]down1[u]、down2[u]down1[u]、down2[u],因为求up[u]up[u]up[u]要用到downdowndown。
答案:min(max(up[i],down1[i]);min(max(up[i],down1[i]);min(max(up[i],down1[i]);
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e4+10,M=2e4+10;
typedef long long LL;
LL n,m,f[N],d1[N],d2[N],up[N];
LL h[N],ne[M],e[M],w[M],idx;
void add(LL x,LL y,LL z)
{
e[idx]=y;ne[idx]=h[x];w[idx]=z;h[x]=idx++;
}
LL dfs_down(LL u,LL fa)
{
for(int i=h[u];i!=-1;i=ne[i])
{
LL j=e[i];
if(j==fa) continue;
LL d=dfs_down(j,u)+w[i];
if(d>=d1[u]) {d2[u]=d1[u];d1[u]=d;}
else if(d>d2[u]) d2[u]=d;
}
return d1[u];
}
void dfs_up(LL u,LL fa)
{
for(int i=h[u];i!=-1;i=ne[i])
{
LL j=e[i];
if(j==fa) continue;
if(d1[u]==d1[j]+w[i])
up[j]=max(up[j],max(up[u],d2[u])+w[i]);
else if(d1[u]!=d1[j]+w[i])
up[j]=max(up[j],max(up[u],d1[u])+w[i]);
dfs_up(j,u);
}
}
int main()
{
cin>>n;memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
LL a,b,c;cin>>a>>b>>c;
add(a,b,c);add(b,a,c);
}
dfs_down(1,-1);
dfs_up(1,-1);
LL minn=1e18;
for(int i=1;i<=n;i++)
minn=min(minn,max(up[i],d1[i]));
cout<<minn;
return 0;
}
本文介绍了如何使用动态规划方法求解树的重心问题,即找到一个节点,使其到树中其他节点的最远距离最近。通过分析节点的下层最远距离(down1)和上层最远距离(up),并给出具体的数据范围和输入输出样例,阐述了解题思路和代码实现。
2963

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



