段并集的连接组件

Connected components in union of segments

提问人:cracra 提问时间:2/23/2020 更新时间:2/24/2020 访问量:586

问:

我在一维数字线上有 N 段(1 ≤ N ≤ 10^5)。每个线段包含所有实数 x,使得起点 x ≤≤终点。

我们可以说,一组段的“并集”是包含在至少一个段中的所有 x 的集合。一组段的“复杂性”是其并集中表示的连接区域的数量。

在段的所有 2^n 个子集上,我们想要计算复杂度的总和。

例:

你有三个段,[1, 6]、[2, 3]、[4, 5],其中 [a, b] a = 起点,b = 终点。

解决方案是 8。以下是每个子集的复杂性: [1,6]⟹1,[2,3]⟹1,[4,5]⟹1

{[1,6],[2,3]}⟹1,{[1,6],[4,5]}⟹1,{[2,3],[4,5]}⟹2

{[1,6],[2,3],[4,5]}⟹1

答案是1+1+1+1+1+2+1=8。

显然,我们不能遍历所有子集(2^N 个子集!谁能给我一个提示或推动我朝着正确的方向前进?

算法 优化 语言无关的 adhoc

评论

3赞 Jonathan Paulson 2/24/2020
这是正在进行的编程竞赛中的一个问题。像这样要求别人为你解决问题,你就是在作弊。请停下来。任何读到的人:请不要帮助这个人作弊。再过几天,比赛就要结束了,这将是一场公平的比赛。

答:

2赞 David Eisenstat 2/23/2020 #1

我假设您熟悉用于计算给定子集的连接分量的标准扫描线算法。

这个想法本质上是同时扫描所有子集。在扫描了开始事件和结束事件之后,有一些子集的扫描点不属于联合。然后,在开始事件中,我们将此计数添加到总复杂度中。2**nse2**(e+n-s)

在 Python 中:

def total_complexity(segments):
    segments = list(segments)
    events = [(segment[i], i) for segment in segments for i in range(2)]
    events.sort()
    total = 0
    ended = 0
    not_started = len(segments)
    for t, is_end in events:
        if is_end:
            ended += 1
        else:
            not_started -= 1
            total += 2 ** (ended + not_started)
    return total


print(total_complexity([(1, 6), (2, 3), (4, 5)]))

评论

1赞 cracra 2/23/2020
您将如何在 O(NlogN) 中解决它?时间限制是一秒,但我基本上最多可以做 10^8 次操作。
0赞 cracra 2/23/2020
或某种程度的 10^8
0赞 cracra 2/23/2020
另外,你的复发中的T是什么?
1赞 David Eisenstat 2/24/2020
@cracra 这个解决方案被破坏了。我用一个希望正确的覆盖了它。
0赞 cracra 2/24/2020
好的,谢谢,我想知道发生了什么!此解决方案的时间复杂度是多少?