趣学算法-2.4高级钟点秘书——会议安排


问题描述:做出合理的安排,能在有限的时间内召开更多的会议

2.4.1 问题分析

在会议安排中,每个会议i都有起始时间bi和结束时间ei,且bi < ei,即一个会议进行的时间为半开区间[bi ,ei)。如果[bi ,ei)与[bj ,ej)均在"有限的时间内",且不相交,则称会议i与会议j相容。也就是说,当bi > ej或bj < ei时,会议i与会议j相容。会议安排问题要求在所给的会议集合中选出最大的相容活动子集,即尽可能在有限的时间内召开更火的会议。
在这个问题中,"有限的时间内(这段时间应该是连续的)"是其中的一个限制条件,也应该是有一个起始时间和一个结束时间(简单化,起始时间可以是会议最早开始的时间,结束时间可以是会议最晚结束的时间),任务就是实现召开更多的满足在这个"有限的时间内"等待安排的会议,会议时间表如表2-6所示。
在这里插入图片描述
会议安排的时间段如图2-7所示。
从图2-7中可以看出,{会议1,会议4,会议6,会议8,会议9},{会议2,会议4,会议7,会议8,会议9}都是能安排最多的会议集合。
要让会议数最多,我们需要选择最多的不相交时间段。我们可以尝试贪心策略:
(1)每次从剩下未安排的会议中选择会议具有最早开始时间且与已安排的会议相容的会议安排,以增大时间资源的利用率。
(2)每次从剩下未安排的会议中选择会议持续时间最短且与已安排的会议相容的会议安排,这样可以安排更多一些的会议。
(3)每次从剩下未安排的会议中选择会议具有最早结束时间且与已安排的会议相容的会议安排,这样可以尽快安排下一个会议。
分析:
如果选择最早开始时间,则如果会议持续时间很长,例如8点开始,却要持续12小时,这样一天就只能安排一个会议;如果选择持续时间最短,则可能开始时间很晚,例如19点开始,20点结束,这样也只能安排一个会议;所以我们最好选择那些开始时间早,而且持续世家按段的会议,即最早开始时间+持续时间最短,就是最早结束时间。
在这里插入图片描述

2.4.2 算法设计

(1)初始化:将n个会议的开始时间、结束时间存放在类中,如果需要知道选中了那些会议,还需要再类中增加会议编号,然后按结束时间从小到大排序(非递减),结束时间相等时,按开始时间从大到小排序(非递增);
(2)根据贪心策略就是选择第一个具有最早结束时间的会议,用last记录刚选中会议的结束时间;
(3)选择第一个会议之后,依次从剩下未安排的会议中选择,如果会议i开始时间大于等于最后一个选中的会议的结束时间last,那么会议i与已选中的会议相容,可以安排,更新last为刚选中会议的结束时间;否则,舍弃会议i,检查下一个会议是否可以安排。

2.4.3 完美图解

1.原始的会议时间表(见表2-7)
在这里插入图片描述2.排序后的会议时间表(见表2-8)
在这里插入图片描述
3.贪心选择过程
(1)首先选择排序后的第一个会议即最早结束的会议(编号为2),用last记录最后一个被选中会议的结束时间,last=4。
(2)检查余下的会议,找到第一个开始时间大于等于last(last=4)的会议,子问题转化为该会议开始,余下的所有会议。如表2-9所示。
在这里插入图片描述
从子问题中,选择第一个会议即最早结束的会议(编号为3),更新last为刚选中会议的结束时间last=7。
(3)检查余下的会议,找到第一个开始时间大于等于last(last=7)的会议,子问题转化为从该会议开始,余下的所有会议。如表2-10所示。
在这里插入图片描述
从子问题中,选择第一个会议即最早结束的会议(编号为7),更新last为刚选中会议的结束时间last=11。
(3)检查余下的会议,找到第一个开始时间大于等于last(last=11)的会议,子问题转化为从该会议开始,余下的所有会议。如表2-11所示。
在这里插入图片描述
从子问题中,选择第一个会议即最早结束的会议(编号为10),更新last为刚选中会议的结束时间last=14;所有会议检查啊完毕,算法结束。如表2-12所示
在这里插入图片描述

2.4.5 实战演练

class Meet:
    def __init__(self, begin, end, num):
        self.begin = begin
        self.end = end
        self.num = num


meet = int(input("请输入会议的数量:"))
meeting = []
for i in range(meet):
    kaishi, jieshu = map(int, input("请输入会议的开始时间和结束时间:").split())
    meeting.append(Meet(kaishi, jieshu, i+1))
meeting.sort(key=lambda x: x.end)  # 根据会议结束时间进行排序(升序)
meet_num = []
meet_num.append(meeting[0].num)  # 将第一个会议加入最佳会议列表
last = meeting[0].end  #
for i in range(meet):
    if meeting[i].begin >= last:  # 如果会议开始时间大于等于最后一个会议的结束时间
        meet_num.append(meeting[i].num)
        last = meeting[i].end  # 重置会议结束时间
print(meet_num)

2.4.6 算法解析及优化拓展

1.算法复杂度分析
(1)时间复杂度:在该算法中,问题的规模就是会议总个数meet。显然,执行次数随问题规模的增大而变化。排序函数的平均时间复杂度为O(nlogn)。随后进行选择会议,贡献最大的为if meeting[i].begin >= last:语句,时间复杂度为O(n),总时间复杂度为O(n+nlogn)=O(nlogn)
(2)空间复杂度:在该算法中,类为输入数据,不计算在空间复杂度内。辅助空间有meet_num、i等变量,则该程序空间复杂度为常数阶,即O(1)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青岛少儿编程-王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值