(D卷,200分)- 找城市(Java & JS & Python & C)

题目描述

一张地图上有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

题目解析

该问题涉及到树结构的分割,给定一棵树,要求删除每个节点后,计算树被分割成的若干个子树中最大的子树大小。目标是找到使得最大子树大小最小的节点。这个最大子树大小被称为该节点的“聚集度”。

步骤解析:

  1. 树结构理解

    • 树是一种无环的连通图,给定 N 个城市和 N-1 条道路构成一棵树。
    • 删除一个节点会使树被分成若干个连通的子树。
  2. 计算节点的聚集度

    • 对于每个节点,删除它后,计算分割成的所有子树的大小。
    • 找到每个节点的最大子树大小,然后选择最小的最大子树大小。
  3. 算法步骤

    • DFS (深度优先搜索):用于遍历树并计算每个节点删除后的子树大小。
    • 子树大小计算:通过 DFS 计算每个节点的子树大小。
    • 聚集度计算:删除节点后,计算剩余的子树大小的最大值。

JAVA算法源码

import java.util.*;

public class TreeAnalysis {
    static List<Integer>[] graph;
    static int[] subtreeSize;
    static int N;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        graph = new ArrayList[N + 1];
        subtreeSize = new int[N + 1];
        for (int i = 1; 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);
        }

        // Perform DFS to calculate subtree sizes
        dfs(1, -1);

        int minDegree = Integer.MAX_VALUE;
        List<Integer> result = new ArrayList<>();

        for (int i = 1; i <= N; i++) {
            int maxSubtree = 0;
            boolean isRoot = true;
            for (int neighbor : graph[i]) {
                if (subtreeSize[neighbor] > subtreeSize[i]) {
                    maxSubtree = Math.max(maxSubtree, subtreeSize[1] - subtreeSize[i]);
                } else {
                    maxSubtree = Math.max(maxSubtree, subtreeSize[neighbor]);
                }
            }
            if (maxSubtree < minDegree) {
                minDegree = maxSubtree;
                result.clear();
                result.add(i);
            } else if (maxSubtree == minDegree) {
                result.add(i);
            }
        }

        Collections.sort(result);
        for (int node : result) {
            System.out.print(node + " ");
        }
        sc.close();
    }

    // DFS to compute subtree sizes
    static void dfs(int node, int parent) {
        subtreeSize[node] = 1;
        for (int neighbor : graph[node]) {
            if (neighbor != parent) {
                dfs(neighbor, node);
                subtreeSize[node] += subtreeSize[neighbor];
            }
        }
    }
}

代码解释

  1. 数据结构

    • graph:邻接表表示树的结构。
    • subtreeSize:记录每个节点的子树大小。
  2. DFS计算子树大小

    • 从根节点开始,递归计算每个节点的子树大小。
  3. 计算每个节点的聚集度

    • 对每个节点,计算删除该节点后形成的各个子树的最大大小。
    • 比较这些最大值,找出最小的最大值对应的节点。
  4. 输出结果

    • 根据计算结果输出聚集度最小的节点,并按升序排列。

这段代码通过 DFS 和简单的遍历操作高效地解决了问题,适用于 N 最大为 1000 的情况。

 


JS算法源码

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

let input = [];
rl.on('line', (line) => {
  input.push(line.trim());
});

rl.on('close', () => {
  const N = parseInt(input[0]);
  const graph = Array.from({ length: N + 1 }, () => []);
  const subtreeSize = Array(N + 1).fill(0);

  for (let i = 1; i < input.length; i++) {
    const [x, y] = input[i].split(' ').map(Number);
    graph[x].push(y);
    graph[y].push(x);
  }

  // Perform DFS to calculate subtree sizes
  function dfs(node, parent) {
    subtreeSize[node] = 1;
    for (const neighbor of graph[node]) {
      if (neighbor !== parent) {
        dfs(neighbor, node);
        subtreeSize[node] += subtreeSize[neighbor];
      }
    }
  }

  dfs(1, -1);

  let minDegree = Infinity;
  let result = [];

  for (let i = 1; i <= N; i++) {
    let maxSubtree = 0;
    let isRoot = true;
    for (const neighbor of graph[i]) {
      if (subtreeSize[neighbor] > subtreeSize[i]) {
        maxSubtree = Math.max(maxSubtree, subtreeSize[1] - subtreeSize[i]);
      } else {
        maxSubtree = Math.max(maxSubtree, subtreeSize[neighbor]);
      }
    }
    if (maxSubtree < minDegree) {
      minDegree = maxSubtree;
      result = [i];
    } else if (maxSubtree === minDegree) {
      result.push(i);
    }
  }

  result.sort((a, b) => a - b);
  console.log(result.join(' '));
});

代码解释

  1. 读取输入

    • 使用 Node.js 的 readline 模块读取输入,输入的第一行是节点数量 N,之后的每一行是连接两个节点的边。
  2. 树结构初始化

    • 使用邻接表 graph 存储树的结构。
    • subtreeSize 用于存储每个节点的子树大小。
  3. DFS计算子树大小

    • dfs 函数从根节点开始递归计算每个节点的子树大小。
  4. 计算每个节点的聚集度

    • 对每个节点,计算删除该节点后形成的各个子树的最大大小。
    • 比较这些最大值,找出最小的最大值对应的节点。
  5. 输出结果

    • 根据计算结果输出聚集度最小的节点,并按升序排列。

此代码适用于在 Node.js 环境中运行,可以处理节点数 N 最多为 1000 的情况。

 


Pyhton算法源码

import sys
sys.setrecursionlimit(2000)

def dfs(node, parent):
    subtree_size[node] = 1
    for neighbor in graph[node]:
        if neighbor != parent:
            dfs(neighbor, node)
            subtree_size[node] += subtree_size[neighbor]

def find_min_max_subtree(n):
    min_max_subtree = float('inf')
    result = []
    for i in range(1, n + 1):
        max_subtree = 0
        for neighbor in graph[i]:
            if subtree_size[neighbor] > subtree_size[i]:
                max_subtree = max(max_subtree, subtree_size[1] - subtree_size[i])
            else:
                max_subtree = max(max_subtree, subtree_size[neighbor])
        if max_subtree < min_max_subtree:
            min_max_subtree = max_subtree
            result = [i]
        elif max_subtree == min_max_subtree:
            result.append(i)
    return result

def main():
    input = sys.stdin.read().strip().split('\n')
    n = int(input[0])
    global graph
    global subtree_size
    graph = [[] for _ in range(n + 1)]
    subtree_size = [0] * (n + 1)

    for line in input[1:]:
        x, y = map(int, line.split())
        graph[x].append(y)
        graph[y].append(x)
    
    dfs(1, -1)
    result = find_min_max_subtree(n)
    print(" ".join(map(str, sorted(result))))

if __name__ == "__main__":
    main()

 

  • 使用递归函数 dfs 计算每个节点的子树大小。
  • find_min_max_subtree 函数计算每个节点删除后的最大子树大小,并找出最小的最大值对应的节点。
  • 读取输入,构建图,计算结果并输出。


C算法源码 

 

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define MAX_N 1000

int graph[MAX_N + 1][MAX_N + 1];
int subtree_size[MAX_N + 1];
int visited[MAX_N + 1];

void dfs(int node, int parent, int n) {
    subtree_size[node] = 1;
    visited[node] = 1;
    for (int i = 1; i <= n; i++) {
        if (graph[node][i] && !visited[i]) {
            dfs(i, node, n);
            subtree_size[node] += subtree_size[i];
        }
    }
}

void find_min_max_subtree(int n) {
    int min_max_subtree = INT_MAX;
    int result[MAX_N];
    int result_size = 0;

    for (int i = 1; i <= n; i++) {
        int max_subtree = 0;
        for (int j = 1; j <= n; j++) {
            if (graph[i][j]) {
                if (subtree_size[j] > subtree_size[i]) {
                    max_subtree = (subtree_size[1] - subtree_size[i] > max_subtree) ? subtree_size[1] - subtree_size[i] : max_subtree;
                } else {
                    max_subtree = (subtree_size[j] > max_subtree) ? subtree_size[j] : max_subtree;
                }
            }
        }
        if (max_subtree < min_max_subtree) {
            min_max_subtree = max_subtree;
            result_size = 0;
            result[result_size++] = i;
        } else if (max_subtree == min_max_subtree) {
            result[result_size++] = i;
        }
    }

    for (int i = 0; i < result_size; i++) {
        if (i > 0) printf(" ");
        printf("%d", result[i]);
    }
    printf("\n");
}

int main() {
    int n;
    scanf("%d", &n);
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            graph[i][j] = 0;
        }
        visited[i] = 0;
        subtree_size[i] = 0;
    }
    
    for (int i = 1; i < n; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        graph[x][y] = 1;
        graph[y][x] = 1;
    }

    dfs(1, -1, n);
    find_min_max_subtree(n);
    
    return 0;
}
  • 使用 dfs 函数计算每个节点的子树大小。
  • find_min_max_subtree 函数计算每个节点删除后的最大子树大小,并找出最小的最大值对应的节点。
  • 读取输入,构建图,计算结果并输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值