百度笔试题 组队

发布时间 2023-09-13 00:29:53作者: 完美二叉树

百度笔试题 组队

题目描述

有n个人,每个人的能力值为\(a_i\),性格值为\(b_i\),要将这n个人分成若干组,每个人只能在一个组内。我们定义两个人的差别值为\(|a_i-a_j|+|b_i-b_j|\).
规定一个差别上限L,如果两个人的差别值不超过L,那么在分组结果中这两人一定会在同一份组内(当然,即使两个人差别值超过L,两个人还是可以在同一小组,只是不超过L的必须在一组)。
现在我们想知道,如果能将所有人分成至少K个非空的小组,规定的差別上限最多为多少。

输入描述

第一行两个正整数n,k,表示人数和分组要求。
接下来两行每行n个整数,表示\(a_1,a_2,...a_n; b_1,b_2,...b_n\)

输出描述

输出一个整数表示最大的差别上限

样例输入

3 2
1 9 3
2 7 8

样例输出

7

思路

首先将问题简化,我们将每个人表示为一个图中的节点,两个人之间的差别值用节点间边的权重表示,这个图是一个完全图。如何找出差別上限的最大值呢?

我们可以在构建图的时候,记录下权重的最大值和最小值,符合条件的差别上限的最大值一定在这个范围之间。最简单的方法,我们可以从小到大一个一个试这些差别上限。

对于某个差别上限L,对图中的每个节点为起点,分别开始dfs搜索,在搜索的过程中,如果达到邻居节点的权重小于等于差别上限L,那么这个节点可达。搜索结束,计算出可以分组的个数,也就是连通分量

如果某次差别上限为L,计算出的分组数小于分组要求k,那么最大的差别上限就是L-1。但是这样做时间复杂度太高,可以用二分查找优化。二分查找

代码

def dfs(x, d_):
    if visited[x]:
        return

    visited[x] = True

    for i in range(n):
        if i == x:
            continue
        if graph[x][i] <= d_:
            dfs(i, d_)


n, k = map(int, input().split())
a_i = [int(i) for i in input().split()]
b_i = [int(i) for i in input().split()]

# 使用邻接矩阵记录图
graph = [[0] * n for i in range(n)]
max_d, min_d = -float('inf'), float('inf')

for i in range(n):
    for j in range(n):
        if i == j:
            continue
        d = abs(a_i[i] - a_i[j]) + abs(b_i[i] - b_i[j])
        graph[i][j] = d
        graph[j][i] = d
        if d > max_d:
            max_d = d
        if d < min_d:
            min_d = d

# 利用二分查找找出最大的差别上限
l, r = min_d - 1, max_d + 1
while l + 1 != r:
    m = (l + r) // 2

    # 计算可以分组的数量
    visited = [False] * n
    connect_num = 0
    for i in range(n):
        if visited[i]:
            continue
        dfs(i, m)
        connect_num += 1

    if connect_num < k:
        r = m
    else:
        l = m

print(l)