首页 > 其他分享 >换根dp

换根dp

时间:2023-04-09 11:47:03浏览次数:29  
标签:int 路径 换根 节点 向下 最长 dp d1

给定一棵树,树中包含 nn 个结点(编号11~nn)和 n−1n−1 条无向边,每条边都有一个权值。

请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。

输入格式

第一行包含整数 nn。

接下来 n−1n−1 行,每行包含三个整数 ai,bi,ciai,bi,ci,表示点 aiai 和 bibi 之间存在一条权值为 cici 的边。

输出格式

输出一个整数,表示所求点到树中其他结点的最远距离。

数据范围

1≤n≤100001≤n≤10000,
1≤ai,bi≤n1≤ai,bi≤n,
1≤ci≤1051≤ci≤105

输入样例:

5 
2 1 1 
3 2 1 
4 3 1 
5 1 1

输出样例:

2
难度:简单
时/空限制:1s / 64MB
总通过数:8103
总尝试数:12486
来源:模板题
算法标签

核心思路:(换根dp)

其实我们看到这个题目的一个想法是可以单独求出来一个节点的最长直径然后对于每一个节点取一个max就好了。以某一个节点作为根的最长路径一定是以他为根的向下的最长路径和向上的最长路径。然后我们发现一个节点的向上的最长路径是和它父节点的向下的最长路径和次长路径决定的。
先看图:

graph(1).png

比如我们要求3的最长向上路径发现其实就是父节点2的一个次长向下路径+w[i],至于为什么不是最长下面有解析,当然图也看得很清楚了。因为会有边重复。
首先看到最大值最小不要立马想二分。这个题目我们可以转换为先求每个节点的一个最长路径,然后再是枚举每一个节点取min就好了。

我们看到求每个节点的最长路径回想到上面那题,但是那题的代码是会超时的。所以这个题目其实是对上一个题目的代码做点优化。

首先可以想怎么对当前节点进行优化呢,假如当前节点是u,当前节点的父节点是father。我们首先思考这个父节点可以对子节点做出一个什么贡献。首先我们当前子节点到父节点的距离确定了也就是w[i].所以我们只需要确定父节点的最长路劲是多少。

父节点的最长路径可以分为两类:

  • 向上的最长路径,这个很好求我们上一题就知道怎么求了,先求根节点到father的最长路径再就是次长路径,然后相加就好了。所以求向上的一个路径也可以转换为求向下的一个路径的问题。
  • 向下的最长路径,这里我们就需要分类讨论了。
    • father节点的最长向下路径经过u,那么我们就只能在u的最长向上路径和次长向下路径取max
    • father节点的最长向下路径不经过u,那么我们就可以在u的最长向下路径和最长向上路径中取max

因为我们是简单路径好马不吃回头草

下面看个图吧:

3.jpg

ok,解释清楚了直接上代码。

#include<iostream>
#include<cstring>
/*
d1[u]:存下u节点向下走的最长路径的长度;
d2[u]:存下u节点向下走的次长路径
p1[u]:存下的是u节点向下走的最长路径是从哪个节点下去的。也就是存的是u节点向下走的最长路径的长子
p2[u]:存下的是u节点向下走的次长路径是从哪一个节点下去的。存的是次长路径的长子。
up[u]:村下的是u节点向上走的最长路径的长度。



*/
using namespace std;
const int N=2e5+10,INF=1e9;
int d1[N],d2[N],up[N], p1[N], p2[N];
int h[N],ne[2*N],e[2*N];
int idx;
int w[N];
int n;
void add(int a,int b,int c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
int dfs_down(int u,int father)//返回u的最长向下路径
{
    d1[u]=d2[u]=-INF;//dp初始化
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(j==father)
        continue;
        int dist=dfs_down(j,u)+w[i];
        if(dist>d1[u])
        {
            d2[u]=d1[u];
            d1[u]=dist;
            p2[u]=p1[u];
            p1[u]=j;
        }
        else if(dist>d2[u])
        {
            d2[u]=dist;
            p2[u]=j;
        }
    }
    if(d1[u]==-INF)//表示的是叶子节点.
    d1[u]=d2[u]=0;
    return d1[u];//因为我们返回的就是最长的向下的路径。
}
void dfs_up(int u,int father)//使用父节点更新子节点向上的最长路径
{
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(j==father)//老样子不可以有回边,要不然会陷入死循环.
        continue;
        if(p1[u]==j)
        up[j]=max(up[u],d2[u])+w[i];
        else
        up[j]=max(up[u],d1[u])+w[i];
        dfs_up(j,u);//因为我们采用的是从上往下所以不需要写一个回溯的做法了,也就是可以把操作放在dfs的上面。
    }
}
int main()
{
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);

    }
    dfs_down(1,-1);
    dfs_up(1,-1);
    int res=INF;
    for(int i=1;i<=n;i++)
    res=min(res,max(d1[i],up[i]));
    cout<<res<<endl;
    return 0;
}

标签:int,路径,换根,节点,向下,最长,dp,d1
From: https://www.cnblogs.com/xyh-hnust666/p/17300062.html

相关文章

  • 「学习笔记」数位 DP
    「学习笔记」数位DP意义不大的题不写了。点击查看目录目录「学习笔记」数位DP概述例题P2657[SCOI2009]windy数思路代码P4317花神的数论题思路P4124[CQOI2016]手机号码思路代码haha数题意思路代码0和1的熟练题意思路代码苍与红的试炼题意思路代码概述数位DP一般......
  • 20230401数位DP
    数位DP数位DP通常指在\([l,r]\)区间中有多少个满足条件\(k\)的个树常见的数据范围都很大也就是说,把数字的枚举,变成数字的构造不要把数字看作是\(10^{18}\)而把数字看作是\(18\)位数的填数过程就是把原本枚举的问题转化为了构造的问题然而数位dp常通过记忆化搜索实现tips:......
  • Java笔记(14) UDP通讯程序Demo
    实现一个简单的UDP通信程序,仅作为笔记使用网络编程中有三要素:IP、端口号和通信协议,分别用来确定对方在互联网上的地址、指定接受数据的软件和确定数据在网络中传输的规则。IP地址IP地址分为IPv4地址和IPv6地址,这里不做讨论。IPv4地址中分为公网地址(万维网使用)和私有地址(局......
  • 数位 dp
    数位\(\text{dp}\)前言谨慎学习此算法。算法讲解AcWing1081.度的数量题意分析:你看到这道题,是不是无从下手?其实题目就是让我们求在\(x\simy\)中,有多少个数分解成\(B\)进制后仅有\(k\)位为\(1\),其余均为\(0\);考虑暴力:从\(x\)枚举到\(y\),将\(i(x\lei\le......
  • 关于 IDP 的五大认知误解
    内部开发者平台(IDP)是近年来在希望加快软件交付和改善开发者体验的企业中得到普及的一个概念。然而,大众对于什么是IDP以及它能为开发者和企业带来什么也有很多困惑和误解。在这篇文章中,我们将尝试解开一些关于平台工程以及IDP的常见误解,以及关于企业该如何避免进入这些误区给出......
  • LightOJ - 1044 Palindrome Partitioning(DP)
    题目大意:给你一个字符串,要求你对字符串进行划分,使得划分出来的子串都是回文串,且子串数量达到最小解题思路:用dp[i]表示前i个字符划分成回文串,需要划分成多少个部分接着枚举j,如果[i,j]回文,那么dp[i]=min(dp[i],dp[j-1]+1)#include<cstdio>#include<cstring>#include<al......
  • UVA - 10003 Cutting Sticks 区间DP
    题目大意:给出一根木棒长l,上面有k个点,要求从这些点切割,每次切割的代价是当前要切割的木棒的长度,求最小的代价解题思路:区间DP:区间动态规划问题一般都是考虑,对于每段区间,他们的最优值都是由几段更小区间的最优值得到,是分治思想的一种应用,将一个区间问题不断划分为更小的区间直至一个......
  • ZOJ - 3469 Food Delivery(区间DP)
    题目大意:有一个餐厅,在X这个位置,送餐速度为v的-1次方,有N个顾客,分别在pos位置,每个顾客都有一个displeasure值,当餐送到该顾客手上时,该顾客的displeasure总值为displeasure值*到手时间问所有顾客的最小displeasure总值和是多少解题思路:首先按位置排个序设dp[i][j][0]为[i,j]这个区......
  • POJ - 1651 Multiplication Puzzle(区间dp)
    题目大意:给你N个数,每次可以选择一个数进行剔除(第一个和最后一个不能选择),选出该数后,sum+=该数左边的数*该数*该数右边的数问最小的sum是多少解题思路:用dp[i][j]表示[i,j]区间被剔除得只剩下i,j的最小sumdp[i][j]=dp[i][k]+dp[k][j]+num[i]*num[k]*num[j]#include......
  • CodeForces - 149D Coloring Brackets(区间DP)
    题目大意:给你一个符合括号规则的字符串,现在要求你将这些括号染色,染色规则如下1.一个括号要么被染成红色,要么被染成蓝色,要么不染2.相邻的括号的颜色不能相同(可以同为无色)3.成对的括号只能有一个被染色问染色的方案数解题思路:0表示不染,1表示红色,2表示蓝色那么成对的括号......