返回
Featured image of post 算法题-网络设备管理

算法题-网络设备管理

叮叮叮!网络设备管理员欢欢在行动欢欢就职于一家庞大的数据管理分析公司公司有一个存储数据的庞大网络,把每个数据存储器看做一。。。

网络设备管理

题目描述

​ 叮叮叮!网络设备管理员欢欢在行动

​ 欢欢就职于一家庞大的数据管理分析公司

​ 公司有一个存储数据的庞大网络,把每个数据存储器看做一个节点,这个存储网络可以看做是一个树型结构,每天有庞大的数据流在节点之间穿梭

​ 随着公司的发展,这个网络越来越庞大,数据的传输速度也越来越慢,通过研究,欢欢发现,每个节点的传输速度,只与与这个节点连接的节点数量有关,比如仅和一个节点连接的节点传输数据会很快,而和 100 个节点连接的节点传输数据会很慢

​ 欢欢准备提交一份研究报告,报告将会指出,若对于网络中的所有节点,与该节点相连的节点数量不超过 d,那么网络的整体传输速度将会大幅提高。

​ 欢欢准备通过添加新的网络设备来降低与某节点相连的节点的数量

​ 简而言之,对于网络设备a,我们可以添加新的设备b,使得原来与a相连的若干节点断开与a的连接并与b连接,并且使a,b连接,显然,添加新的网络设备后,这个网络仍旧是一个树形结构这样通过添加若干新的网络设备,我们可以把所有网络设备的相连网络设备数量降低到不超过d台 (包括与新添加的网络设备相接的网络设备数量不超过 d)

​ 欢欢发现,有很多种解决方案

​ 聪明的你知道欢欢最少添加多少台网络设备吗?

​ 注意: 欢欢添加新的设备后,网络的结构仍保持为树形结构

输入

​ 单组输入 ​ 第一行两个正整数 \(n\), \(d$ \)(1\le n\le 10^5,3\le d\le n)\(​ 接下来\)n-1\(行,每行两个正整数$a\)\(b$ \)(1\le a, b\le n)\(,说明设备$a\)与设备\(b\)相连接,数据保证设备网络为树形结构。

输出

​ 一个正整数,最小添加的网络设备数量,注意欢欢可以添加0台设备。

样例

样例输入 样例输出
10 3
2 1
3 1
4 1
5 2
6 1
7 6
8 5
9 7
10 6
1

AC代码

#include <iostream>
#define MAXN 100005

using namespace std;

int arr[MAXN];

int main(){
    int n,d;
    cin>>n>>d;
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        arr[a]+=1;
        arr[b]+=1;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(arr[i]>d){
            int tmp = (d-1)*2;
            if(arr[i]-tmp<=0){
                ans+=1;
            }
            else if((arr[i]-tmp)%(d-2)==0)
                ans += 1 + (arr[i]-tmp)/(d-2); 
            else
                ans += 1 + (arr[i]-tmp)/(d-2)+1; 
        }
    }
    cout<<ans;
    return 0;
}

正确性证明

先给出样例的示意图

其中红色数字表示与这个节点直接相连的节点的个数。显然只有1号节点连了大于3个节点,我们可以新增一个节点A,将2、3号与A相连,4、6号不变,然后将1与A相连,现在1与A连了三个节点,符合要求。不过这不是唯一的连法。

这种有最大连接节点的结构,很容易让人回想起烷烃。显然的,饱和烷烃的碳链无论怎么排布,所连的氢原子的数目不会改变。每个碳原子也都会连四个原子。

类比到这道题,我们要做的,就是将形如下图的点(假设上限为连3个)

变为如下的一些点,当然这里的点怎么排布都不影响,只要他最大的利用了链接上限,就是答案。

解释一下核心代码

for(int i=1;i<=n;i++){
        if(arr[i]>d){//枚举超过链接上限的节点
            int tmp = (d-1)*2; //点链两端,能“向外”链接d-1个点,必须要向“内部”链接一个点,才能构成点链,这个arr[i]-tmp得到的是还需要“向外”链接的数量。
            if(arr[i]-tmp<=0){//特判一下,如果只用新增一个节点,并且有一个节点没有占满上限
                ans+=1;
            }
            else if((arr[i]-tmp)%(d-2)==0)//内部每个节点都只能“向外”链接d-2个节点,如果能全部占满每个内部节点的上限,ans如下
                ans += 1 + (arr[i]-tmp)/(d-2); 
            else//不能占满则ans如下
                ans += 1 + (arr[i]-tmp)/(d-2)+1; 
        }