2023华为OD机试 (B卷)|200分 城市聚集度(C++ Java JavaScript Python)

2023华为OD机试 (B卷)|200分 城市聚集度(C++ Java JavaScript Python)
题目描述

一张地图上有N个城市,城市和城市之间有且只有一条道路相连,要么直接相连,要么通过其他城市中转相连(可中转一次或多次)。城市与城市之间的道路都不会成环。
当切断通往某城市i的所有道路后,地图上将分成多个连通的城市群,设该城市i的聚集度为DPi of Polymerization), DPi = max(城市群1的城市个数,城市群2的城市个数,...城市群m的城市个数)。 请找出地图上DP值最小的城市(即找到城市j,使得DPj = min(DP1,DP2...DPn))

提示:如果有多个城市都满足条件,这些城市都要找出来(可能存在多个解)
提示:DPi的计算,可以理解为已知一个树,删除某个节点后,生成的多个字树,求解多个字树节点数的问题

输入描述

每个样例,第一行有一个整数N,表示有N个节点,1 <=N <=1000
j接下来的N-1行每行有两个整数x,y,表示城市x与城市y连接。1 <= x , y <= N

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

输入5
1 2
2 3
3 4
4 5
输出3

说明

1
2
3
4
5

对于城市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

Java

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    static class UnionFindSet {
        private int[] father; // 存储每个节点的父节点

        public UnionFindSet(int n) { // 初始化并查集,每个节点的父节点为自己
            father = new int[n];
            for (int i = 0; i < n; i++) father[i] = i;
        }

        public int find(int x) { // 查找x的祖先节点,路径压缩优化
            if (father[x] != x) {
                father[x] = find(father[x]);
            }
            return father[x];
        }

        public void unionSet(int x, int y) { // 合并x和y所在的集合
            int x_fa = find(x);
            int y_fa = find(y);

            if (x_fa != y_fa) { // 如果x和y不在同一个集合中,则将y的祖先节点设为x的祖先节点
                father[y_fa] = x_fa;
            }
        }
    }

    public static void main(String[] args) throws java.lang.Exception {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        int[][] relations = new int[n - 1][2]; // 存储n-1条关系
        for (int i = 0; i < n - 1; i++) { // 输入n-1条关系
            relations[i][0] = sc.nextInt();
            relations[i][1] = sc.nextInt();
        }

        int min_dp = Integer.MAX_VALUE; // 最小的最大连通块大小
        List<Integer> city = new ArrayList<>(); // 最小的最大连通块所在的城市

        for (int i = 1; i <= n; i++) { // 枚举每个城市作为特殊城市
            UnionFindSet ufs = new UnionFindSet(n + 1); // 初始化并查集
            for (int[] relation : relations) { // 将与特殊城市相连的边删除
                int x = relation[0], y = relation[1];
                if (x == i || y == i) continue;
                ufs.unionSet(x, y);
            }

            Map<Integer, Integer> count = new HashMap<>(); // 统计每个连通块的大小
            for (int f : ufs.father) {
                f = ufs.find(f);
                count.put(f, count.getOrDefault(f, 0) + 1);
            }

            int dp = 0; // 最大连通块大小
            for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
                dp = Math.max(dp, entry.getValue());
            }

            if (dp < min_dp) { // 如果当前最大连通块大小比之前的最小值还小,则更新最小值和最小值所在的城市
                min_dp = dp;
                city.clear();
                city.add(i);
            }
            else if (dp == min_dp) { // 如果当前最大连通块大小与之前的最小值相等,则将城市加入最小值所在的城市列表
                city.add(i);
            }
        }

        for (int c : city) { // 输出最小的最大连通块所在的城市
            System.out.print(c + " ");
        }
    }
}

Javascript

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

class UnionFindSet {
  constructor(n) {
    this.father = new Array(n);
    for (let i = 0; i < n; i++) {
      this.father[i] = i;
    }
  }

  find(x) {
    if (this.father[x] !== x) {
      this.father[x] = this.find(this.father[x]);
    }
    return this.father[x];
  }

  unionSet(x, y) {
    const x_fa = this.find(x);
    const y_fa = this.find(y);

    if (x_fa !== y_fa) {
      this.father[y_fa] = x_fa;
    }
  }
}

let n;
let relations = [];

rl.on('line', (line) => {
  if (!n) {
    n = parseInt(line);
  } else {
    const [x, y] = line.split(' ').map(Number);
    relations.push([x, y]);
    if (relations.length === n - 1) {
      rl.close();
    }
  }
});

rl.on('close', () => {
  let min_dp = Infinity;
  let city = [];

  for (let i = 1; i <= n; i++) {
    const ufs = new UnionFindSet(n + 1);
    for (const [x, y] of relations) {
      if (x === i || y === i) continue;
      ufs.unionSet(x, y);
    }

    const count = new Map();
    for (let f of ufs.father) {
      f = ufs.find(f);
      count.set(f, (count.get(f) || 0) + 1);
    }

    let dp = 0;
    for (const c of count.values()) {
      dp = Math.max(dp, c);
    }

    if (dp < min_dp) {
      min_dp = dp;
      city = [i];
    } else if (dp === min_dp) {
      city.push(i);
    }
  }

  console.log(city.join(' '));
});

C++

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <climits>

using namespace std;

class UnionFindSet {
public:
    vector<int> father; // 存储每个节点的父节点

    UnionFindSet(int n) { // 初始化并查集,每个节点的父节点为自己
        father.resize(n);
        for (int i = 0; i < n; i++) father[i] = i;
    }

    int find(int x) { // 查找x的祖先节点,路径压缩优化
        if (father[x] != x) {
            return father[x] = find(father[x]);
        }
        return x;
    }

    void unionSet(int x, int y) { // 合并x和y所在的集合
        int x_fa = find(x);
        int y_fa = find(y);

        if (x_fa != y_fa) { // 如果x和y不在同一个集合中,则将y的祖先节点设为x的祖先节点
            father[y_fa] = x_fa;
        }
    }
};

int main() {
    int n;
    cin >> n;

    vector<vector<int>> relations(n - 1, vector<int>(2)); // 存储n-1条关系
    for (int i = 0; i < n - 1; i++) { // 输入n-1条关系
        cin >> relations[i][0] >> relations[i][1];
    }

    int min_dp = INT_MAX; // 最小的最大连通块大小
    vector<int> city; // 最小的最大连通块所在的城市

    for (int i = 1; i <= n; i++) { // 枚举每个城市作为特殊城市
        UnionFindSet ufs(n + 1); // 初始化并查集
        for (const auto& relation : relations) { // 将与特殊城市相连的边删除
            int x = relation[0], y = relation[1];
            if (x == i || y == i) continue;
            ufs.unionSet(x, y);
        }

        unordered_map<int, int> count; // 统计每个连通块的大小
        for (int f : ufs.father) {
            f = ufs.find(f);
            count[f]++;
        }

        int dp = 0; // 最大连通块大小
        for (const auto& c : count) {
            dp = max(dp, c.second);
        }

        if (dp < min_dp) { // 如果当前最大连通块大小比之前的最小值还小,则更新最小值和最小值所在的城市
            min_dp = dp;
            city.clear();
            city.push_back(i);
        }
        else if (dp == min_dp) { // 如果当前最大连通块大小与之前的最小值相等,则将城市加入最小值所在的城市列表
            city.push_back(i);
        }
    }

    for (int c : city) { // 输出最小的最大连通块所在的城市
        cout << c << " ";
    }
    cout << endl;

    return 0;
}

python

class UnionFindSet:
    def __init__(self, n):
        self.father = [i for i in range(n)]

    def find(self, x):
        if self.father[x] != x:
            self.father[x] = self.find(self.father[x])
        return self.father[x]

    def unionSet(self, x, y):
        x_fa = self.find(x)
        y_fa = self.find(y)
        if x_fa != y_fa:
            self.father[y_fa] = x_fa

n = int(input())
relations = [list(map(int, input().split())) for _ in range(n - 1)]

min_dp = float('inf')
city = []

for i in range(1, n + 1):
    ufs = UnionFindSet(n + 1)
    for x, y in relations:
        if x == i or y == i:
            continue
        ufs.unionSet(x, y)

    count = {}
    for f in ufs.father:
        f = ufs.find(f)
        count[f] = count.get(f, 0) + 1

    dp = max(count.values())

    if dp < min_dp:
        min_dp = dp
        city = [i]
    elif dp == min_dp:
        city.append(i)

print(*city)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一个字符串 s ,请你找出其中最长的不含重复字符的子串长。 示例: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长为 3。 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长为 1。 思路析: 用一个 hash 表存储每个字符最后一次出现的位置。遍历字符串,记录当前子串的起始位置 start 和当前位置 i,当遇到重复字符时,更新 start 的位置。最后更新最长子串的长。 代码实现: Python: class Solution(object): def lengthOfLongestSubstring(self, s): """ :type s: str :rtype: int """ hash_map = {} res = 0 start = 0 for i in range(len(s)): if s[i] in hash_map and hash_map[s[i]] >= start: start = hash_map[s[i]] + 1 hash_map[s[i]] = i res = max(res, i - start + 1) return res Java: class Solution { public int lengthOfLongestSubstring(String s) { int[] hash_map = new int[256]; int res = 0; int start = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (hash_map[c] >= start) { start = hash_map[c] + 1; } hash_map[c] = i; res = Math.max(res, i - start + 1); } return res; } } C++: class Solution { public: int lengthOfLongestSubstring(string s) { vector<int> hash_map(256, -1); int res = 0; int start = 0; for (int i = 0; i < s.size(); i++) { char c = s[i]; if (hash_map[c] >= start) { start = hash_map[c] + 1; } hash_map[c] = i; res = max(res, i - start + 1); } return res; } }; 总结: 这道题考察了字符串的基础操作和 hash 表的使用。通过本题的练习,可以在实际开发中更加熟练地使用 hash 表,提高代码效率和可读性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值