相容问题——贪心算法

相容问题——贪心算法

1. 问题

有n项活动申请使用同一个礼堂,每项活动有一个开始时间和一个截止时间。如果任何两个活动不能同时举行,问如何选择这些活动,从而使得被安排的活动数量达到最多。
设S={1,2,…,n}为活动的集合,si和fi分别为活动i的开始和截止时间,i=1,2,…,n
定义:活动i和j相容<==>si≥fj或sj≥fi,i≠j
求S最大的两两相容的活动子集A。

2.解析

在这里插入图片描述

k=3
(1) 选择活动1:截止时间最早:活动2、3与活动1不相容,活动4与活动1相容;
(2) 选择活动4:活动5、6、7与活动4不相容,活动8与活动4相容;
(3) 选择活动8:活动9、10与活动8不相容。

证明对于任意正整数k,算法的前k步选择都能导致一个最优解。

定理:算法执行到第k步,选择k项活动,那么存在最优解A包含i1=1,i2,….,ik

证明(数学归纳法):将S中的活动按照截止时间递增顺序排列。

(1) k=1时,算法选择了活动 1.(算法执行到第一步,选择结束时间最短的活动作为第一个活动)

设A={i1,i2,…,ij}是问题的一个最优解,

·如果i1=1,那么存在最优解包含了活动1,得证

·如果i1≠1,那么用1替换i1得到AA=(A-{i1}∪{1}

A’和A的活动个数相等,活动1比i1结束得更早,因此活动1和i2,…,ij等活动也相容,于是A’也是问题的一个最优解,因此存在最优解包含了活动1.得证。

A={i1,i2,…,ij}

A`={1,i2,…,ij}

f1<fi1<si2→f1<si2→1和i2相容

(2) 假设对于任意正整数k,命题正确。

令i1=1,i2,…,ik是算法前k步顺序选择的活动,根据归纳假设,一个规模为n的问题的最优解,当算法步骤为k时,i1=1,i2,…,ik为前k个最优解:

1)构建问题最优解A:由归纳假设,问题S存在一个最优解A由前k个和S中剩下活动中选出部分,即

A={i1,i2,…,ik}∪B

其中 B 必然是 S 中剩下活动中与i1,i2,…,ik相容的活动Sb(令Sb是 S 中剩下活动中与i1,i2,…,ik相容的活动)的最优解。

证明(反证法):如果 B 不是Sb的最优解,必然存在 B’是Sb的最优解, 即|B’|>|B|,则A={i1,i2,…,ik}∪B’将比 A 的活动更多,与A是最优解矛盾。因此,B 是Sb的最优解。

2)分离最优解B的一个最早结束任务:由(1)得算法第一步选择结束 时间最早的活动总是导致一个最优解。对于子问题Sb存在一个包含选择结束时间最早的活动ik+1的最优解B*={ik+1,….},B和 B 都是最优解,于是

A={i1=1,i2,…,ik}∪B={i1=1,i2,…,ik}∪B={i1=1,i2,…,ik,ik+1}∪(B*-{ik+1})包含前k+1的活动,得证。

其他贪心策略

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
活动安排问题是指在一组互相竞争的活动中选出最大的相容活动集合贪心算法是解决这个问题的一种有效方法。以下是C语言实现活动安排问题贪心算法的步骤: 1.将所有活动按照结束时间从早到晚排序。 2.选择第一个活动作为已安排的活动。 3.对于剩余的活动,如果该活动的开始时间晚于或等于已安排的活动结束时间,则将该活动加入已安排的活动集合中。 4.重复步骤3,直到所有活动都被考虑过。 以下是C语言实现活动安排问题贪心算法的代码实现: ```c #include <stdio.h> #include <stdlib.h> // 活动结构体 struct Activity { int start; int end; }; // 比较函数,用于排序 int cmp(const void* a, const void* b) { return ((struct Activity*)a)->end - ((struct Activity*)b)->end; } // 贪心算法求解活动安排问题 void activitySelection(struct Activity activities[], int n) { // 按照结束时间从早到晚排序 qsort(activities, n, sizeof(struct Activity), cmp); // 第一个活动一定会被选中 int i = 0; printf("(%d, %d) ", activities[i].start, activities[i].end); // 选择其他活动 for (int j = 1; j < n; j++) { if (activities[j].start >= activities[i].end) { printf("(%d, %d) ", activities[j].start, activities[j].end); i = j; } } } int main() { // 测试数据 struct Activity activities[] = {{1, 4}, {3, 5}, {0, 6}, {5, 7}, {3, 8}, {5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 13}, {12, 14}}; int n = sizeof(activities) / sizeof(activities[0]); // 求解活动安排问题 activitySelection(activities, n); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值