朴素的贪心法简析及案例

文章目录


朴素的贪心法是一种在每一步选择中都采取在当前看来最优(或局部最优)的选择,从而希望导致全局最优解的算法策略。这种策略不考虑整体解决方案的空间,而是基于这样一种假设:通过一系列局部最优的选择,最终能够达到全局最优解。然而,这种假设并不总是成立,因此贪心算法在某些问题上可能无法得到最优解,但在其他一些特定问题上却能高效地找到最优或近似最优解。

贪心算法的基本原则可以总结为以下几个方面:

  1. 最优子结构:问题的最优解包含其子问题的最优解。
  2. 贪心选择性质:在每一步选择中,所作的决策都是当前状态下最好或最优的选择,且不会影响后续步骤做出更优决策的能力。
  3. 无后效性:当前的决策仅依赖于当前状态,与过去的决策和子问题的解决方式无关。

适用贪心策略的经典问题包括:

  • 活动选择问题:从多个有重叠时间的活动中选择最多的非重叠活动参加,每次选择结束时间最早的未结束活动。
  • 哈夫曼编码:构建最优前缀码,每次合并频率最小的两个结点。
  • Prim算法Kruskal算法求最小生成树:Prim算法每次选择连接已选择顶点的最小权边,Kruskal算法每次选择所有边中权值最小且不形成环的边。
  • Dijkstra算法求单源最短路径:每次从未加入最短路径集合的顶点中选择距离源点最近的顶点加入。

需要注意的是,虽然这些算法基于贪心策略,但它们的成功应用往往依赖于问题的具体性质,确保局部最优选择能导向全局最优解。在设计贪心算法时,必须仔细分析问题是否满足贪心选择的条件。对于不满足这些条件的问题,如旅行商问题(TSP),直接使用贪心策略通常得不到最优解。
当然,除了上面提到的应用,贪心算法还适用于其他多种场景,这里列举几个额外的例子来进一步说明贪心策略的应用范围:

  • 币值兑换问题:给定不同面额的硬币和一个总金额,每次选择尽可能大的硬币进行兑换,直到凑足总金额。这个策略在大多数情况下能有效减少硬币的数量,但需要确保硬币序列是提前排序好的,并且存在某种机制可以找回(如果选择了过大的硬币)。

  • 背包问题的一个变种分数背包问题,在这个问题中,每个物品有一个价值和一个重量,但与经典的0/1背包问题不同,可以取物品的一部分。贪心策略是按照单位重量的价值比从高到低排序物品,然后尽可能多地选取这些物品直至背包装满。这种方法不能保证全局最优解,但对于分数背包问题,它可以得到一个相对不错的近似解。

  • 任务调度问题:在有截止日期的任务调度中,如果任务之间没有依赖关系,可以按照完成任务所需的最短时间来优先安排,这是一种贪心策略。尽管这可能不是所有情况下的最佳策略,但在简化版的问题中,它可以帮助快速确定一个合理的调度方案。

尽管贪心算法在某些问题上表现优秀,但它的局限性也很明显,主要体现在:

  • 全局最优性难以保证:除非问题具有特定的性质(如贪心选择性质和最优子结构),否则贪心算法可能得到非最优解。
  • 对问题的结构敏感:算法的有效性高度依赖于问题的定义和约束条件,有时候微小的变化就可能导致算法失效。
  • 缺乏回溯机制:一旦做出选择,贪心算法不会撤销之前的决定去探索可能更好的全局解决方案。

因此,在实际应用中,选择是否采用贪心算法,以及如何设计贪心策略,都需要深入分析问题的具体特点。

下面是一个使用Python编写的解决活动选择问题的贪心算法示例代码:

def activitySelection(start_times, end_times):
    # 将活动按结束时间从小到大排序,同时保持开始时间与之对应
    activities = sorted(zip(start_times, end_times), key=lambda x: x[1])
    selected_activities = [activities[0]]  # 初始化选择的第一个活动

    for current in activities[1:]:
        # 如果当前活动的开始时间大于前一个选择活动的结束时间,则可以添加该活动
        if current[0] >= selected_activities[-1][1]:
            selected_activities.append(current)

    # 提取活动的编号(假设原始输入是活动编号而非时间)
    # 注意:此处为了简化,假设输入就是按活动编号顺序给出的,实际情况可能需要调整以匹配原始活动编号
    selected_activity_nums = [i+1 for i, _ in enumerate(selected_activities)]
    
    return selected_activity_nums, len(selected_activities)

# 示例输入
start_times = [1, 3, 0, 5, 8, 5]
end_times =   [2, 4, 6, 7, 9, 9]

# 调用函数
selected_activities, total_selected = activitySelection(start_times, end_times)

print(f"Selected Activities: {selected_activities}")
print(f"Total Number of Selected Activities: {total_selected}")

这段代码首先将活动的开始和结束时间配对,并按结束时间进行排序。接着,遍历排序后的活动列表,如果当前活动的开始时间大于前一个已选活动的结束时间,则将其加入到已选活动列表中。最后,输出被选中的活动编号(这里简化处理为按索引+1作为活动编号)及总数。

请注意,这个示例为了简洁,直接使用了时间作为排序和比较的依据,实际应用中,你可能需要根据具体情况调整数据结构和逻辑。

😍😍 海量H5小游戏、微信小游戏、Web casualgame源码😍😍
😍😍试玩地址: https://www.bojiogame.sg😍😍
😍看上哪一款,需要源码的csdn私信我😍

————————————————

​最后我们放松一下眼睛
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

极致人生-010

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

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

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

打赏作者

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

抵扣说明:

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

余额充值