安排具有固定开始和结束时间的最大数量任务

时间:2016-02-13 14:17:23

标签: python python-2.7 schedule np

我正在尝试创建一个只使用python内置模块的调度函数,这些模块将返回最大数量的非重叠约会。函数的输入是列表列表,内部列表包含2个整数元素,即开始和结束时间。无法更改开始和结束时间,如果一次会议的开始时间与另一次会议的开始时间相同,则不会将其视为重叠。例如:

输入:

meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]
max_meetings(meetings)

输出:

4

我现在使用的代码只是暴力破解它,并且在内存和执行时间方面都非常低效。尽管使用类很有趣,但似乎有更好的方法。

def max_meetings(meetings):
    '''
    Return the maximum number of non overlapping meeting that I can attend

    input:
        meetings - A list of lists. the inner list contains 2 values, the start
            time[0] and the end time[1].

    returns:
        total - The total number of non overlapping meetings that I can attend.
    '''

    num_meetings = len(meetings)
    assert (num_meetings <= 100)

    appt_obj = [Appt(o) for o in meetings]

    total = 0
    for appt in appt_obj:
        schedule = Schedule()
        schedule.add_meeting(appt)
        counter = 0
        for comp_appt in appt_obj:
            counter += 1
            schedule.add_meeting(comp_appt)
            # If there isnt a chance, break to save some time
            if ((num_meetings - counter) < (total - schedule.meetings)):
                break

        if schedule.meetings > total:
            total = schedule.meetings

    return total


class Schedule:
    '''
    A class to hold my entire schedule. Can add
    appointments
    '''
    def __init__(self):
        self.times = set()
        self.meetings = 0

    def add_meeting(self, appt):
        points = range(appt.start, appt.end)
        if any(x in self.times for x in points):
            pass
        else:
            # This for loop also seems unnecessary
            for p in points:
                self.times.add(p)
            self.meetings += 1


class Appt:
    '''
    A class for an appointment
    '''

    def __init__(self, meeting):
        assert (meeting[0] >= 0)
        assert (meeting[1] <= 1000000)
        self.start = meeting[0]
        self.end = meeting[1]

2 个答案:

答案 0 :(得分:1)

类通常运行速度稍慢但更容易理解;你的代码中的问题不是类,它是一个糟糕的算法(你可以编写一个超级优化的机器代码bubblesort并且它仍然会很慢)。

此问题非常适合动态编程:

  • 按结束时间的升序排列所有会议

  • 维护一个结束时间列表,例如lst[n] = t,其中n是会议次数,t是可能的最早结束时间。让lst[0] = float("-inf")作为无会议占位符。

  • 要插入会议,找到n的最低lst[n] <= start,如果lst[n + 1]不存在或大于end,请{{1} }}

  • 完成后,会议的最大数量为lst[n + 1] = end

根据您的示例,

len(lst) - 1

你最终应该

meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]

应该被理解为“最多可以有1次会议结束1次,最多2次会议结束2次,最多3次会议结束3次,最多4次会议结束5次”。

请注意,这并不能告诉您会议的哪个组合会给出该结果,或者有多少这样的组合是可能的 - 只有至少存在一个这样的组合。

修改:尝试以下操作:

lst = [-inf, 1, 2, 3, 5]

一样运行
from bisect import bisect

class Meeting:
    # save about 500 bytes of memory
    #  by not having a __dict__
    __slots__ = ("start", "end")

    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __lt__(self, other):
        return self.end < other.end

def max_meetings(meetings):
    meetings.sort()    # Meeting.__lt__ provides a natural sort order by meeting.end

    # -1 is just a "lower than any actual time" gatepost value
    lst = [-1]

    for m in meetings:
        # find the longest chain of meetings which this meeting can follow
        i = bisect(lst, m.start)

        if i == len(lst):
            # new most-meetings value
            lst.append(m.end)
        elif m.end < lst[i]:
            # new earliest finish-time for 
            lst[i] = m.end

    # what is the most meetings we can attend?
    # print(lst)
    return len(lst) - 1

答案 1 :(得分:0)

如何在迭代中从原始列表中删除项目,然后只检查剩下的项目:

def overlaps(one, other):
    if one[0] <= other[0] and other[1] <= one[1]:
        return True
    if other[0] <= one[0] and one[1] <= other[1]:
        return True
    else:
        return False

def max_meetings(slots):
    unique = 0
    while len(slots) > 0:
        meeting = slots.pop(0)
        for slot in slots:
            if overlaps(meeting, slot):
                break
        else:
            unique +=1
    return unique

meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]
print(max_meetings(meetings))

如果存在overlaps没有覆盖的边缘情况,那么您可以轻松地扩展逻辑,因为它在单独的函数中整齐地解耦。