首页 > 其他分享 >华为OD- 找城市-2024年OD(D卷)

华为OD- 找城市-2024年OD(D卷)

时间:2025-01-12 20:04:31浏览次数:3  
标签:子树 int graph OD subtree 2024 华为 大小 节点

题目描述

一张地图上有n个城市,城市和城市之间有且只有一条道路相连:要么直接相连,要么通过其它城市中转相连(可中转一次或多次)。城市与城市之间的道路都不会成环

当切断通往某个城市 i 的所有道路后,地图上将分为多个连通的城市群,设该城市i的聚集度为DPi(Degree of Polymerization),DPi = max(城市群1的城市个数,城市群2的城市个数,…城市群m 的城市个数)。

请找出地图上DP值最小的城市(即找到城市j,使得DPj = min(DP1,DP2 … DPn))

提示:如果有多个城市都满足条件,这些城市都要找出来(可能存在多个解

提示:DPi的计算,可以理解为已知一棵树,删除某个节点后;生成的多个子树,求解多个子数节点数的问题。

输入描述

每个样例:第一行有一个整数N,表示有N个节点。1 <= N <= 1000。

接下来的N-1行每行有两个整数x,y,表示城市x与城市y连接。1 <= x, y <= N

输出描述

输出城市的编号。如果有多个,按照编号升序输出。

用例
输入5 1 2 2 3 3 4 4 5
输出3
说明
对于城市3,切断通往3的所有道路后,形成2个城市群[(1,2),(4,5)],其聚集度分别都是2。DP3 = 2。对于城市4,切断通往城市4的所有道路后,形成2个城市群[(1,2,3),(5)],DP4 = max(3,1)= 3。依次类推,切断其它城市的所有道路后,得到的DP都会大于2,因为城市3就是满足条件的城市,输出是3。
输入6 1 2 2 3 2 4 3 5 3 6
输出2 3
说明将通往2或者3的所有路径切断,最大城市群数量是3,其他任意城市切断后,最大城市群数量都比3大,所以输出2 3

解题思路

问题描述

给定一个 nnn 个节点的树,求出所有可能的「重心节点」。重心节点定义为:移除该节点后,剩余各部分中的最大节点数量最小。

数学逻辑
  1. 重心定义

    • 对于每个节点 iii,移除节点后,将树分成若干个子树。
    • 对每个子树,计算其节点数。
    • 找出所有节点中,移除后子树中最大节点数最小的节点。
  2. 递归思想

    • 使用 DFS 遍历树,计算每个节点的子树大小(包括自己)。
    • 对于每个节点 iii:
      • 遍历其所有相邻节点(子节点)。
      • 递归地计算每个子节点的子树大小。
      • 更新当前节点的最大子树节点数(包括移除当前节点后剩下的子树)。
  3. 最终目标

    • 遍历所有节点,找到移除该节点后最大子树大小最小的节点集合。

 python源码:

from collections import defaultdict

# 深度优先搜索(DFS)计算每个节点的子树大小和最大子树大小
def dfs(city, parent, graph, subtree_sizes, n):
    size = 1  # 初始化当前节点的子树大小
    max_subtree = 0  # 当前节点的最大子树大小

    # 遍历当前节点的所有邻居
    for neighbor in graph[city]:
        if neighbor == parent:  # 跳过父节点,避免回溯
            continue
        # 递归计算子节点的子树大小
        child_size = dfs(neighbor, city, graph, subtree_sizes, n)
        size += child_size  # 累加子节点的大小到当前节点
        max_subtree = max(max_subtree, child_size)  # 更新最大子树大小
    
    # 计算移除当前节点后剩余部分的大小
    max_subtree = max(max_subtree, n - size)
    subtree_sizes[city] = max_subtree  # 保存当前节点的最大子树大小
    return size  # 返回当前节点的子树大小

# 主函数:计算树的重心
def getResult():
    # 输入节点数量
    n = int(input())
    # 用邻接表表示树
    graph = defaultdict(list)

    # 输入树的边
    for _ in range(n - 1):
        x, y = map(int, input().split())
        graph[x].append(y)
        graph[y].append(x)
    
    # 初始化子树大小数组
    subtree_sizes = [0] * (n + 1)
    min_dp = n  # 初始化最小的最大子树大小为 n
    result = []  # 存储所有可能的重心节点

    # 遍历所有节点,计算每个节点的最大子树大小
    for i in range(1, n + 1):
        dfs(i, -1, graph, subtree_sizes, n)  # 以 i 为根节点计算子树大小
        if subtree_sizes[i] < min_dp:  # 如果找到更小的最大子树大小
            min_dp = subtree_sizes[i]
            result = [i]  # 更新结果为当前节点
        elif subtree_sizes[i] == min_dp:  # 如果相等,添加到结果列表
            result.append(i)
    
    # 按升序输出所有重心节点
    print(" ".join(map(str, sorted(result))))

# 调用主函数
getResult()

java源码:

import java.util.*;

public class m3 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 输入节点数量
        int n = sc.nextInt();
        
        // 初始化图的邻接表表示
        ArrayList<Integer>[] graph = new ArrayList[n + 1];
        for (int i = 0; i <= n; i++) {
            graph[i] = new ArrayList<>();
        }
        
        // 输入图的边并建立邻接表
        for (int i = 0; i < n - 1; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            graph[x].add(y);
            graph[y].add(x);
        }
        
        // 计算并输出重心节点
        System.out.println(findMinDP(n, graph));
    }

    // 查找重心节点的方法
    public static String findMinDP(int n, ArrayList<Integer>[] graph) {
        int minDP = Integer.MAX_VALUE; // 初始化最小的最大子树大小
        ArrayList<Integer> result = new ArrayList<>(); // 存储重心节点的结果列表

        // 遍历所有节点,逐一计算每个节点的最大子树大小
        for (int i = 1; i <= n; i++) {
            int[] maxSubtreeSize = new int[1]; // 存储当前节点的最大子树大小
            boolean[] visited = new boolean[n + 1]; // 标记访问过的节点
            visited[i] = true; // 当前节点被访问
            int largestSubtree = 0; // 当前节点的最大子树大小

            // 遍历当前节点的所有邻居节点
            for (int neighbor : graph[i]) {
                // 通过 DFS 计算子树大小
                int subtreeSize = dfs(neighbor, graph, visited, maxSubtreeSize);
                largestSubtree = Math.max(largestSubtree, subtreeSize); // 更新最大子树大小
            }

            // 判断是否更新最小的最大子树大小
            if (largestSubtree < minDP) {
                minDP = largestSubtree; // 更新最小的最大子树大小
                result.clear(); // 清空之前的结果
                result.add(i); // 添加当前节点为重心
            } else if (largestSubtree == minDP) {
                result.add(i); // 如果相等,则添加当前节点
            }
        }
        
        // 按升序排列重心节点,并以字符串形式返回
        result.sort(Comparator.naturalOrder());
        return String.join(" ", result.stream().map(String::valueOf).toArray(String[]::new));
    }

    // 深度优先搜索(DFS)计算子树大小
    public static int dfs(int node, ArrayList<Integer>[] graph, boolean[] visited, int[] maxSubtreeSize) {
        visited[node] = true; // 标记当前节点为访问过
        int size = 1; // 当前节点的子树大小为 1(自身)
        
        // 遍历所有相邻节点
        for (int neighbor : graph[node]) {
            if (!visited[neighbor]) { // 如果邻居节点未被访问
                int subtreeSize = dfs(neighbor, graph, visited, maxSubtreeSize); // 递归计算子树大小
                size += subtreeSize; // 将子树大小累加到当前节点的子树大小
                maxSubtreeSize[0] = Math.max(maxSubtreeSize[0], subtreeSize); // 更新最大子树大小
            }
        }
        
        return size; // 返回当前节点的子树大小
    }
}

标签:子树,int,graph,OD,subtree,2024,华为,大小,节点
From: https://blog.csdn.net/hxyh888/article/details/145080976

相关文章

  • P11365 Ynoi2024 新本格魔法少女りすか
    P11365Ynoi2024新本格魔法少女りすか神奇的压位树状数组……思路序列区间查询操作,考虑分块。处理好散块与整块之间的贡献即可。散块对散块:每次询问的区间产生的散块用树状数组计算贡献,复杂度\(O(\summ_i\sqrt{n\logn})\)。整块对散块(区间):枚举整块,处理\(ressum_i\)......
  • leetcode2902 和带限制的子多重集合的数目
    给定数组nums[n]和整数l,r,nums中的元素可能会重复,要求从nums中选择若干个元素,其元素和在[l,r]内,有多少种不同方案,结果对1E9+7取模。注:空集合的结果为0,相等的元素之间没有区别。1<=n<=2E4;0<=nums[i]<=2E4;sum(nums[i])<=2E4;0<=l<=r<=2E4分析:1、存在相等元素,且没有区别,可以......
  • [PCIE5.0] 4.2.8 Compliance Pattern in 8b/10b Encoding
    这段文字描述的是在PCIe或类似高速接口协议中,Polling.Compliance子状态的具体要求,特别是合规模式(CompliancePattern)在传输过程中的处理方式。这个过程主要是通过SKPOrderedSet来验证链路的合规性,确保链路在高频率下的稳定性、可靠性和时序准确性。我们来逐步解读这......
  • LeetCode:112.路径总和
    LeetCode:112.路径总和解题思路在深度优先遍历的过程中,记录当前路径的节点值的和。在叶子节点处,判断当前路径的节点值的和是否等于目标值。解题步骤深度优先遍历二叉树,在叶子节点处,判断当前路径的节点值的和是否等于目标值,是就返回true。遍历结束,如果没有匹配,就返回false。varh......
  • LeetCode:102.二叉树的层序遍历
    LeetCode:102.二叉树的层序遍历解题思路层序遍历顺序就是广度优先遍历。不过在遍历时候需要记录当前节点所处的层级,方便将其添加到不同的数组中。/***Definitionforabinarytreenode.*functionTreeNode(val,left,right){*this.val=(val===undefined?0:......
  • leetcode3333 找到初始输入字符串II
    用键盘输入字符时,可能因为在一个键上停留太久,导致同一个字符被输入多次。给定word表示最终显示的字符串,以及整数k,表示希望输入字符串的最少长度,求希望输入串的总方案数,对1E9+7取模。1<=|word|<=5E5;1<=k<=2000;word只包含小写字母分析:1、假设最终串的长度为n,对其分组循环,把相......
  • Codeforces Round 734 (Div. 3) 题解
    建议开题顺序:A,B1,B2,C,E,F,D1,D2。A.PolycarpandCoins记\(k=\min(c1,c2)\),则\((c1-k)\times1+(c2-k)\times2+k\times3=n\)。注意到\(n\mod3\)为\(0,1,2\)。所以我们\(|c1-c2|\)最多为\(1\),只需要将\(n\mod3\)给\(1\)或\(2\)即可。B1.WonderfulColo......
  • LeetCode:111.二叉树的最小深度
    LeetCode:111.二叉树的最小深度解题思路求最小深度,考虑使用广度优先遍历。在广度优先遍历过程中,遇到叶子节点,停止遍历,返回节点层级。解题步骤广度优先遍历整棵树,并记录每个节点的层级。遇到叶子节点,返回节点层级,停止遍历。//dfsvarminDepth=function(root){if(!root......
  • VS Code+Gitee+Picgo实现图床
    在VSCode中结合Gitee图床和PicGo插件,解决Markdown文档插入图片的问题。步骤一、在VSCode中安装Picgo插件步骤二、在系统中安装Picgo软件进入PicGo官网:https://molunerfinn.com/PicGo/。下载最新版本.exe文件。安装完成后,打开PicGo,点击插件设置,搜索gitee,安装gitee-uploader......
  • VS Code中创建Markdown模板
    在VSCode中Ctrl+N新建文件时,键入简洁的前缀,自动生成Markdown文件模板。配置VSCode用户设置Ctrl+Shift+P搜索OpenUserSettings.json在json文件中添加以下代码:"[markdown]":{"editor.quickSuggestions":true}创建Markdown模板Ctrl+Shift+P搜索snippets......