算法导论_16.1 活动选择(贪心算法)

贪心算法

最优化问题的算法往往都包含一系列的步骤,每个步骤都要做出最优化的选择(相对全局来说也是最优的);
贪心算法所做的选择看起来是当前最佳的,(相对于局部来讲是最佳的, 相对于全局来讲并不是最佳的),贪心算法希望通过局部的最优解得到一个全局最优解;
注意:贪心算法有时候你能够产生全局最优解,有时候并不能产生全局最优解;

贪心算法是先做出选择,然后再求解子问题,先选择后求解会导致:
1) 由于先做选择,选择的比较标准不是子问题的解,因此求得的可能不是全局最优解;
2) 由于经过了选择之后再求解子问题,子问题的数目减少为O(1), 可以降低时间复杂度;
一种称为拟阵的组合结构, 对于这种结构, 贪心算法总是能够给出最优解;

最小生成树是贪心算法的一个经典的例子;

一、活动选择问题

n个活动, S = {a1, a2, …, an};
每个活动有,
开始时间: s1, s2, …, sn
结束时间: f1, f2, …, fn;
活动选择问题是选择具有最多兼容的活动的集合;

1) 寻找活动选择问题的最优子结构
首先假设其子问题空间是一维的, 即S(1, i)的最优解由S(1, i-1)的最优解构成。但是发现S(1, i)的最优解可能是由S(2, i-1) 或是S(3,i-1)的最优解构成。因此,会发现子问题空间是一维是不够的, 子问题空间是二维的;

其子问题空间是二维的,对于活动S(i, j), 需要做出j-i-1种选择;
选择活动ak(其中i<=k<=j), 那么:
S(i, j) = S(i, k) + {ak} + S(k, j);
S(i, j) 具有最优化结构, 可以使用动态规划算法得到,时间复杂度是O(n^3)
假设c[i, j] 为问题S(i, j)中最大兼容活动的个数,有递归式:
在这里插入图片描述
其边界条件是当S(i, j)是空集的时候, c[i, j] = 0;
因此,完整的递归式是:
在这里插入图片描述
子问题空间是二维的, 对每个子问题都要进程O(n)次选择,因此总的时间复杂度是O(n^3);

2) 将动态规划转化为贪心算法

再次分析活动选择问题, 有两个发现:
对于任何非空子问题S(i, j), 设am是S(i, j)中具有最早结束时间的活动,那么:
1) 活动am一定是S(i, j)的最大兼容活动子集;
2) 子问题S(i, m)为空, 选择了am,那么子问题S(m, j)是唯一可能的非空;
首先了解, 最优子结构会随着原问题最优解的子问题数目以及确定子问题是的选择(受子问题空间以及每个子问题的选择影响);
动态规划中, 每个子问题有j-i-1种选择;
贪心算法中, 通过选择集合中最早结束时间的活动,使得S(i, m)为空, 这样就只用考虑子问题S(m, j). 在解决子问题中,贪心算法只考虑了一种选择,并且子问题空间也变为一维的;这样时间复杂度就是O(n);
最优子结构会随着原问题最优解的子问题数目以及确定子问题时的选择数目变化;
此外,由于子问题空间将为一维,子问题的选择只有一种,贪心算法在这里可以选用自顶向下解决,使得代码更加简单,时间复杂度从O(n^3)变为O(n);

贪心算法求解活动选择:
为了解决子问题S(i, j), 选择S(i, j)中具有最早结束时间的am, 并将子问题S(m, j)的最优解中的活动集合加入到S(i, j)的解中去;

贪心算法与动态规划的区别:
仔细分析问题,简化问题的子问题空间和选择,使得最优化结构简化,从而得到局部最优解;
问题最优化结构的简化会降低算法的时间复杂度;

二、 求解活动选择问题的代码

1) 使用动态规划求解活动选择问题
子问题空间是二维的S(i, j);
问题的选择是在S(i, j)选择一个ak,之后原问题的解 S(i, j) = S(i, k) + {ak} + S(k, j);
分析原问题个子问题的类型,可以发现子问题的长度小于原问题的长度(j-i), 因此建议在外循环使用长度l,最先求解长度l =2的所有子问题,长度l = 1的问题是边界条件;
确定选择的是ak的时候, 还要分别确定S(i,k) 和S(k, j), 原则是前缀子问题的最后一个活动的结束时间要早于ak的开始时间, ak的结束时间要早于后缀子问题第一个活动的开始时间;

#include <stdio.h>
#include <stdlib.h>

#define N 11
int s[N] = {
    1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
int f[N] = {
    4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };

//使用m数组存储(i, j)的活动选择数
int m[N + 1][N + 1];

void DynamicActivitySelect(int low, int high) {
   
	//边界条件
	if (low >= high)
		return;
	for (int i = 1; i <= N
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,可以使用贪心算法来解决多种问题,如活动安排、哈夫曼编码、背包问题、最短路径、最优装载和最小生成树等。其中,活动安排问题是贪心算法的一个经典应用之一。贪心算法通过每一步选择局部最优解来达到全局最优解的目标。 关于Python实现贪心算法活动安排问题,有一篇文章提供了详细的介绍和实例代码。这篇文章讨论了如何使用Python实现贪心算法解决活动安排问题,可以作为参考。 总结来说,Python可以用来实现贪心算法,并且可以通过贪心算法解决活动安排等一系列问题。如果你对Python实现贪心算法感兴趣,可以参考相关的资料和文章进一步学习和实践。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [greedy_哈夫曼编码_活动安排_背包问题_python_贪心算法_](https://download.csdn.net/download/weixin_42691388/27658494)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [浅谈Python实现贪心算法活动安排问题](https://download.csdn.net/download/weixin_38623255/12871404)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值