关于 网络延时 一题的思路+代码(树的后序遍历&DP)

题目来源:Acwing-3215.网络延时

题目描述

给定一个公司的网络,由 n 台交换机和 m 台终端电脑组成,交换机与交换机、交换机与电脑之间使用网络连接。
交换机按层级设置,编号为 1 的交换机为根交换机,层级为 1。
其他的交换机都连接到一台比自己上一层的交换机上,其层级为对应交换机的层级加 1。
所有的终端电脑都直接连接到交换机上。
当信息在电脑、交换机之间传递时,每一步只能通过自己传递到自己所连接的另一台电脑或交换机。
请问,电脑与电脑之间传递消息、或者电脑与交换机之间传递消息、或者交换机与交换机之间传递消息最多需要多少步。

输入描述

输入的第一行包含两个整数 n,m,分别表示交换机的台数和终端电脑的台数。
第二行包含 n−1 个整数,分别表示第 2、3、……、n 台交换机所连接的比自己上一层的交换机的编号。第 i 台交换机所连接的上一层的交换机编号一定比自己的编号小。
第三行包含 m 个整数,分别表示第 1、2、……、m 台终端电脑所连接的交换机的编号。

输出描述

输出一个整数,表示消息传递最多需要的步数。

数据范围

前 30% 的评测用例满足:n≤5,m≤5。
前 50% 的评测用例满足:n≤20,m≤20。
前 70% 的评测用例满足:n≤100,m≤100。
所有评测用例都满足:1≤n≤10000,1≤m≤10000。

输入样例1

4 2
1 1 3
2 1

输出样例1

4

在这里插入图片描述

输入样例2

4 2
1 1 3
2 1

输出样例2

4

在这里插入图片描述

输入样例3

15 10
1 7 1 2 2 1 1 4 2 1 1 11 13 2
11 3 8 9 13 10 6 12 7 12

输出样例3

6

OP

样例3是测试组之一,反映了一些前两个样例没有的情况,下面会具体解释。

思路

首先对于这道题,交换机与电脑几乎没有区别,只是电脑一定作为末端,所以在处理时不需要特殊区分。

对于题求的消息传递最多需要的步数,可以分为两大种情况,一种是如样例1、2图示,最长距离两点在同一节点下不同的子树,另一种情况是两点存在亲子关系,即一个点在以另一点为根的子树的叶节点上。

对于第二种情况,消息传递最多需要的步数显然是根节点(1号交换机)与深度最大的叶节点(电脑或交换机)构成的对。

第一种情况,我们可以做如下处理:

对于最小值的情况,我们可以看成是该节点下 不同子树的 两个深度最深的 叶子的 深度之和。

我们可以后序遍历该树,对于每一个节点的深度先初始化为0。对于节点 i ,其父节点 fa[ i ] 的深度 dpl[ fa[ i ] ] = max( dpl[ fa[ i ] ] , dpl[ i ]+1 ) ,这样我们便可以得到每一个点的所在深度(到以其为根的子树的最远叶节点的距离)。

再对于所有度>=2 的节点,找到 dpl 最大的两个叶节点,则以该点(度>=2的点)为根的子树的题求量则为 dplmax1 + dplmax2 + 2 ,再更新目前题求量的最大值即可。

在构建后序遍历时,不能直接通过序号降序遍历,如样例三,则会出现一些问题:7在3之前被遍历,而后序遍历则是3在7前。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dpl[20004],fa[20004]={0,0};//fa存上级节点
vector<int>son[20004];//存下级节点
stack<int>order;
void eno(int x)//构建后序遍历栈
{
    order.push(x);
    int i;
    for(i=0;i<son[x].size();i++)
    {
        eno(son[x][i]);
    }
}
int main()
{
    memset(dpl,0,sizeof dpl);
    int n,m,i,j,g,ans=0;
    cin>>n>>m;
    for(i=2;i<=n;i++)//接收交换机
    {
        scanf("%d",&g);
        fa[i]=g;
        son[g].push_back(i);
    }
    for(;i<=n+m;i++)//接收电脑
    {
        scanf("%d",&g);
        fa[i]=g;
        son[g].push_back(i);
    }
    eno(1);
    while(order.size())
    {
        i=order.top();
        order.pop();
        dpl[fa[i]]=max(dpl[fa[i]],dpl[i]+1);//更新上级节点的dpl
        if(son[i].size()>=2)//度>=2
        {
            int mx1=0,mx2=0;
            for(j=0;j<son[i].size();j++)//找最大的两个叶节点dpl
            {
                if(dpl[son[i][j]]>mx1)
                {
                    mx2=mx1;
                    mx1=dpl[son[i][j]];
                }
                else if(dpl[son[i][j]]==mx1||dpl[son[i][j]]>mx2)
                {
                    mx2=dpl[son[i][j]];
                }
            }
            ans=max(ans,mx1+mx2+2);//更新题求量
        }
    }
    ans=max(ans,dpl[1]);//与第二大类情况做比较
    cout<<ans;
    return 0;
}

ED

\

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值