如何计算两次出席人数的最小数量

时间:2012-08-10 12:10:52

标签: algorithm time

我会尽可能地清楚。

我有一个有两次,开始和结束的事件。 (时间为24小时格式) 例如,此事件从8开始,到12结束。

通过此活动,我有一份工作时间表的人员列表。 这是一个例子:

  • 人1:从8:00到10:00
  • 人2:从10:00到12:00
  • 人3:从6:00到15:00
  • 人4:从8:00到9:00
  • 人5:从9:30到12:00

现在,我需要知道在整个活动中我至少有多少人。

就我而言,它将 2 ,因为:

  • 人1&人2相互补充
  • 第3人将永远存在
  • 4人和4人之间有喘气。 5,在9:00到9:30之间,所以在这段时间里,4人和4人之间没有人。 5将出席。

如果我用时间解释一下:

  • 从8:00到9:00:人员1,3,4
  • 从9:00到9:30:第1,3个人
  • 从9:30到10:00:1,3,5,
  • 从10:00到12:00:第2,3,5人

大多数情况下,该活动将有3人,但最低为2人。

如何使用算法获取此数字,我无法理解这一点。

我考虑过以分钟为单位转换时间(我不会在分钟之内),在事件时间设置范围(从8 * 60到12 * 60),并将每个人的存在添加为新范围,然后计算每分钟,有多少片(1片= 1人)。但我觉得这样效率不高,因为我必须将切片计算为4 * 60分钟:/(从8 - > 12)。

你会怎么做?

5 个答案:

答案 0 :(得分:2)

获取人员编号i的开始和结束时间,并将其命名为s_ie_i

将所有这些放在列表times中。然后执行以下操作:

# start_time contains the start time of the event
# end_time contains the start time of the event
sort(times) # When doing this sort, make sure that if a s_i
            # is at the same time as a e_j, put the s_i first.

current_number = number of people who're there at start_time
remove all times that match start_time from times

minimum_number = current_number

for time in times:
    if time is an s_i: current_number += 1

    if time is an e_i:
        current_number -= 1
        if current_number < minimum_number and time < end_time:
            minimum_number = current_number

此操作的运行时间如下:

n为人数。

我们花费O(n lg n)时间进行排序,因为我们只有2n次排序。

然后,我们花费O(n)时间迭代时间,不断地工作。

总的来说,O(n lg n)。请注意,此运行时间与其跨越的时间间隔完全无关,并且仅取决于您正在处理的人数。

这是sweep line algorithm的一种形式。我们横扫时间,只停留在感兴趣的点(s_ie_i s。)

请注意,我们在s_i之前对e_j s进行排序的原因如下:

如果我们不这样做,那么想象我们有两个人:鲍勃在这里是8-10,爱丽丝在这里是10-12。那么,如果我们不仔细排序,我们可能会得到以下列表:

times = [(s_Bob, 8), (e_Bob, 10), (s_Alice, 10), (e_Alice, 12)]

如果我们这样排序,那么看起来好像鲍勃在10离开后没有人离开。但是,爱丽丝在那里,因为她同时到达。因此,为了防止这种情况,我们将它排序为开始时间在结束时间之前,如果是平局:

times = [(s_Bob, 8), (s_Alice, 10), (e_Bob, 10), (e_Alice, 12)]

答案 1 :(得分:0)

快速回答,或许每当有人开始/完成工作时都会更新人数?

例如,在t0,您将其设置为知道谁在那里。每隔一分钟或更好,每个请假/进入日期(已排序)都会记下当前新人数。

答案 2 :(得分:0)

如果您的活动中没有太多人,您可以去做

之类的事情
minimum -> infinity
for each person in persons do:
    intersections -> 0
    for each other person in persons do:
        if other person start time <= person start time
            if other person end time >= person start time
                intersections++
        else if other person start time < person end time
            intersections++
    if intersections < minimum
        minimum = intersections

答案 3 :(得分:0)

hauron的回答帮助我创建了这个解决方案。

这是伪代码,因为没有语言标记。

有一个开始时间的排序列表,以及结束时间的排序列表
为零当前人员启动一个计数器 还有一个计数器,用于正无限的最小人数 将最近的时间作为活动的初始时间

一起浏览列表,选择第一个开始时间和第一个结束时间的早期

如果越早开始时间,请递增计数器并删除第一个开始时间 否则,越早结束时间,递减计数器并删除第一个结束时间

如果刚刚使用的时间与最近时间不同,请检查最低人数计数器(例如,如果有3个人同时进入,请等待更新最低人数计数器,直到处理所有三个人) 如果当前人员小于最低人数,请将最低人数设置为当前人员

更新最近的时间
重复,直到两个列表都为空

最低人数应该有你的答案

答案 4 :(得分:0)

我认为你的算法应该是这样设计的:

  • 从8:00开始:1号,3号,4号人员
  • 从9:00开始:1号人员
  • 从9:30开始:1号,3号,5号人员
  • 从10:00开始:第2,3,5人

首先将事件的开始和结束时间添加到 接下来,遍历您的成员构建 set 的开始和结束时间(设置防止重复)。 然后遍历集合中的项目,并针对集合中的每个元素检查每个成员,以查看他的开始时间是否> =并且结束时间是&gt;那么集合中的项目。有一个内部迭代的计数器来跟踪给定时间的人数,并且在两次迭代之外都有一个变量,用于跟踪给定时间内的最小人数。在伪代码中:

var set : set
var event_start : time = 8:00
var event_end : time = 12:00
set.add(event_start)
foreach(person in people)
    set.add(person.start)
    set.add(person.end)
var min : int = people.size
var time_of_min : time
foreach time in set
    var num_people : int = 0
    foreach person in people
        if person.start >= time && person.end > time
            num_people++
    if num_people < min
        min = num_people
        time_of_min = time
// Handle the special case of the ending time
var num_people_at_end : int = 0
foreach person in people
    if person.end == event_end
        num_people_at_end++
if num_people_at_end < min
    min = num_people_at_end
    time_of_min = event_end