编程题四大算法思想(三)——贪心法:找零问题、背包问题、任务调度问题、活动选择问题、Prim算法

文章目录

  • 贪心法
    • 找零问题(change-making problem)
      • 贪心算法要求
        • 基本思想
        • 适合求解问题的特征
    • ==背包问题==
      • 0/1背包问题
        • 0/1背包问题——贪心法
      • 分数背包问题
    • 任务调度问题
    • 活动选择问题
      • 活动选择——贪心法
        • 最早结束时间优先——最优性证明
    • ==Prim算法==

贪心法

  我在当前情况下,我把我做到最好。我也不管全局如何,整体如何。我就考虑我现在的这一个,或者这一小部分怎样最好。

  • 贪心技术是一种设计算法的通用策略。
  • 贪心技术的基本思想:
    • 基于贪心选择准则,每次得到局部最优的选择。
    • 希望利用局部最后得到全局最优解。
    • 贪心选择性质:局部最优可以得到全局最优。
  • 找到正确的贪心选择准则是设计贪心算法的关键。
    • 不同的贪心选择准则可以得到不同的结果。

打个比方,我现在有几种选择:

学编程、打游戏、读书、去外面玩、去兼职、……

如果我的目的是提高自己的知识水平,那起码对于现在的这些选择来说,我选择“学编程”或者“读书”就是最优的。

只是说当前这一步怎么走是最优的,也并没有去管后面的路怎么走。

比如你说选择“打游戏”,后面可能也会更成功,但是不管这个。

找零问题(change-making problem)

  • 给定无限多不同面额的硬币 d 1 > . . . > d m d_1>...>d_m d1>...>dm,对于总额 n n n,如何找到最少的硬币数目?
  • 问题:目标函数和约束条件是什么?

例如:

d 1 = 25 c , d 2 = 10 c , d 3 = 5 c , d 4 = 1 c ,而且 n = 48 c d_1=25c,d_2=10c,d_3=5c,d_4=1c,而且n=48c d1=25c,d2=10c,d3=5c,d4=1c,而且n=48c

我们可能想,要使得硬币数目最少,那简单啊。

先紧着面额最大的来凑就行了。

先拿个25c的、再拿两个10c的,5c的没法拿,于是再拿3个1c的。

于是得到贪婪解:<1,2,0,3>

我们这个策略就是,很简单,先紧着最大的拿。

但是我们虽然这样做了,而且貌似可行。

但是实际上,它对于大多数情况而言,这样可能是没问题的;但是没法保证所有情况啊,你没法保证对于所有情况、任意某一种情况,这样都没问题。

有一些情况,你这样做,可能就压根不是最优解了。

但是:

  • 对大多数常用的硬币面额都可以得到最优解。
  • 对任意硬币面额,有可能不是最优解。

例如:

d 1 = 25 c , d 2 = 10 c , d 3 = 1 c 而且 n = 30 c d_1=25c,d_2=10c,d_3=1c而且n=30c d1=25c,d2=10c,d3=1c而且n=30c

那么你还按照上面的规则,

先拿个25c的,然后拿五个1c的。——此时是6个硬币。

但实际上我们可以看出,直接拿三个10c的就够了,而且只用3个硬币。

所以可见,我们刚才的那种简单的想法:先紧着大面额的拿。

这种方法,可能在某些情况下没毛病,但是在有些情况下就不对了、不是最优解了。

**那咋办呢。**是不是我的想法、我的策略设计的有问题呢?

那到底咋样弄,才能对于所有情况都能得到最优解呢?

我们可以用回溯法。(不是讲贪心吗,咋又说回溯了?——后面再说这个问题)


  • **贪婪法:**建议通过一系列步骤来构造问题的解,每一步对目前构造的部分解做一个扩展,直到获得问题的完全解。(完全解,不是最优解)
  • 必须满足:可行局部最优不可取消

贪心算法要求

  • 可行的:即它必须满足问题的约束。
  • 局部最优:它是当前步骤中所有可行选择中最佳的局部选择。
  • 不可取消:即选择一旦做出,在算法的后面步骤中就无法改变了。

就像人生中的一些选择一样,就是贪心算法么,每次选的是局部最优,而且选了之后就没法取消了。

  在每一步中,它要求“贪婪”地选择最佳操作,并希望通过一系列局部的最优选择,能够产生一个整个问题的(全局的)最优解。

基本思想

  • 从问题的某一个初始解出发,通过一系列的贪心选择(当前状态下的局部最优选择),逐步逼近给定的目标,尽可能快地求得更好的解。
  • 在贪心算法(greedy method)中也采用逐步构造最优解的方法。在每个阶段,都做出一个按某个评价函数最优的决策,该评价函数最优称为贪心准则(greedy criterion)。
  • 贪心算法的正确性,就是要证明按贪心准则求得的解是全局最优解。
  • 贪心算法不能对所有问题都得到全局最优解。
  • 但是对于许多问题,它能够产生全局最优解。如单源最短路径问题,最小生成树问题等。

适合求解问题的特征

  • **贪心选择性质:**可通过局部最优(贪心)选择达到全局最优解。
    • 通常以自顶向下的方式进行,每次选择后将问题转化为规模更小的子问题。
    • 该性质是贪心法使用成功的保障,否则得到的是近优解。
  • 最优子结构性质:问题的最优解包含它的子问题的最优解
    • 并不是所有具有最优子结构性质的问题都可以采用贪心策略。
    • 往往可以利用最优子结构性质来证明贪心选择性质。

背包问题

  • 0-1背包问题

  给定n种物品和一个背包。物品i的重量是 W i W_i Wi,其价值为 V i V_i Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

0-1背包问题,对于一个物品,0就是不拿它,1就是拿它。

在选择装入背包的物品时,对每种物品只有两种选择,要么装入背包、要么不装入背包。不能将一个物品装入背包多次,也不能只装入某物品的一部分。

  • 背包问题

  与0-1背包问题类似,所不同的是,在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n

背包问题,也叫“分数背包问题”,对于一个物品,物品太大了,背包剩余空间不够了,此时我可以把物品拆下来、把一部分放进去。

0/1背包问题

  • 已知
    • 背包容量C>0
    • n个物品,体积 w i > 0 w_i>0 wi>0,价值 p i > 0 f o r i = 1 , . . . , n p_i>0\ for\ i=1,...,n pi>0 for i=1,...,n
  • 确定 { 1 , 2 , . . . , n } \{1,2,...,n\} {1,2,...,n}的子集,满足:

m a x ∑ i ∈ A p i , s u b j e c t t o ∑ i ∈ A w i ≤ C max\sum_{i∈A}p_i,subject\ to\ \sum_{i∈A}w_i≤C maxiApi,subject to iAwiC

0/1背包问题——贪心法

  • 有以下几种贪心选择准则:

    • 最大价值优先——先选择最值钱的物品。

    紧着最值钱的先往上放。

    • 最小体积优先

    紧着最小体积的先放,想装的多。

    • 最大体积优先

    想着一般大的东西都比较值钱?所以先紧着大件先放?

    • 最大单位价值优先

这四个规则都有一定道理,那我们该选哪种呢?选最大价值优先?选最大单位价值优先?

  • 没有一种方法能保证得到最优解

最大价值优先

image-20230901221752374

lb是重量单位,上面是价钱)

可见,最大价值优先,放进来的不一定是最优解。

最小体积优先

image-20230901221933373

可见,最小体积优先,放进来的也不一定是最优解。

最大体积优先

image-20230901222120953

可见,最大体积优先得到的也不一定是最优解。

最大单位价值优先

image-20230901222244231

可见,这个也不一定能得到最优解。


分数背包问题

  • 对于0/1背包问题,没有最优的贪心算法。
  • 分数背包问题:可以将第i个物品的一部分放入背包。
  • 对于分数背包问题,贪心算法是其不二选择,该算法基于最大单位价值的选择准则。(感觉有点类似于微积分里的微元思想)

这个就没啥好犹豫的了,我先紧着最大单位价值的往里面放,放不下整个物品的时候,我把当前最大单位价值的物品切出来一块往里面放。

这样最后包里放的肯定是价值最大的情况。

  • 贪心算法过程:
    • 降序排序 v i / w i v_i/w_i vi/wi
    • 根据排序次序增加物品,直到这个物品装完,或是超出背包容量。
    • 如果背包没有满,选择下一个物品开始装。

最优解证明

  • 证明

  我们首先假设我们有一个最优解 A 1 A_1 A1,那么我们首先找到 A 1 A_1 A1里面平均价值最高的物品 a m a_m am,然后我们将用商品里面平均价值最高的物品 a 1 a_1 a1 a m a_m am进行全部替换或者部分替换得到解 A 2 A_2 A2,又因为 v 1 w 1 ≥ v m w m \frac{v_1}{w_1}≥\frac{v_m}{w_m} w1v1wmvm,所以 A 2 A_2 A2的总价值高于 A 1 A_1 A1的总价值,这与 A 1 A_1 A1是最优解矛盾,于是得到 A 1 A_1 A1里面包含平均价值最高的物品。


  • 小数背包问题还具有贪心选择性质,用贪心法求解更简单、更快速。
  • 0-1背包问题用贪心法求解不一定能得到最优解。

任务调度问题

  • 9个任务需要调度,每个任务运行时间为3,5,6,10,11,14,15,18,20

如果只有一个处理器,那就没啥说的,每个任务看看按照什么规则往里放就行了,反正最后总时间是一样的。

但是如果有多个处理器呢?

  • 有三个处理器执行这些任务。

当然,对于贪心而言,我们对这一问题也可以有很多种贪心策略。

  • 贪心准则:先运行时间最长的任务。

image-20230901225656081

image-20230901225708372

每次把当前需要运行最长时间的任务,分配给当前任务时间最短的处理器。

image-20230901225829341

因此,三个处理器执行这些任务,花费35分钟时间。

这个解决方法不错,但是我们可能还可以有更好的策略。

  • 另一种贪心准则:优先运行最短任务

image-20230901230002189

image-20230901230054831

这个方式还不如刚才那个,这个需要花费40分钟。

最优解

image-20230901230149638

折腾半天都不是最好的,那我们看看最优解到底是什么样的,如上图所示。

  • 这个解为什么是最优的?

很明显么。因为三个处理器刚好平均分了所有任务的总时长,没有任何的浪费。

  但是,可见,若想得到这样的一种解。你要付出的代价就会很高了。

  有必要么,实际解决一个问题来说,这样去搞,可能没这个必要。你找到最优解了之后,最优解固然能够帮你节约时间;但是不要忽视了,你寻找这个最优解也要花时间。你为了找一个最优解去节约那一点点时间,然后你花了大量的时间在寻找到最优解上,得不偿失。

类似上图中这个最优解,是咋找到的?可能是暴力穷举吧,或者是什么方法。总之很耗时间才能找出来的。

  实际上我就用一种贪心策略,去做,就拉倒了。虽然可能不是最优,但是接近最优差不多就行了。

  对于一些特殊的问题,贪心算法能直接找出其最优解,能直接获取最优解那当然更好了。

  总之贪心算法可能找到的不是最优解,而只是局部最优解;但是它的实现是很简单的,不会耗费太多时间。


  同时,我们在贪心,贪的过程中,也可以利用回溯法的思想,对一些没必要继续探讨下去的情况进行剪枝,而没必要全部贪到底、再去排除。也就是贪心法配合回溯法进行使用。

活动选择问题

image-20230902113155194

  • 这个就是活动选择问题。

我选择哪些活动,能够让活动数量最多?

image-20230902113312495

image-20230902113456345

image-20230902113650572

活动选择——贪心法

  • 贪心法选择准则:
    • 最早开始时间优先
    • 最小持续时间优先
    • 最早完成时间优先
  • 哪个准则更有效?

image-20230902113801677

最早开始时间优先。

假设有一个从0开始的活动,但是它持续时间巨长。

那这显然不是最优解。

image-20230902113836981

如上图。

这个持续时间最小,但是可能因为做了它,它刚好介于两个活动邻接点,导致两个活动都没法做。

显然也不是最优解。

image-20230902113931701

image-20230902114012301

最早结束时间是不是能达到这个问题的最优解?

实际上,按最早结束时间优先,基本上都能取到最优解。

怎么证明这种策略的正确性?怎么知道上面的例子不是它的特例?

  • 需要证明贪心法的正确性。

最早结束时间优先——最优性证明

**定理:**如果活动 a 1 a_1 a1在所有活动中具有最早结束时间,则最优解中一定包含 a 1 a_1 a1

证明:

  • A A A是最优解, a 1 a_1 a1是贪心法选择的最早结束时间的活动。如果 a 1 ∈ A a_1∈A a1A,则定理得证。
  • 如果 a 1 ∉ A a_1∉A a1/A,我们证明 A ∗ = A − { a } + { a 1 } A^*=A-\{a\}+\{a_1\} A=A{a}+{a1}是另一个包含 a 1 a_1 a1的最优解,而 a a a A A A中具有最早结束时间的活动。
  • 因为活动的结束时间已排序好, f ( a 1 ) ≤ f ( a ) f(a_1)≤f(a) f(a1)f(a)。假设 f ( a 1 ) ≤ s ( a ) f(a_1)≤s(a) f(a1)s(a),如果我们把 a 1 a_1 a1加到 A A A,意味着 A A A不是最优的。所以 s ( a ) < f ( a 1 ) s(a)<f(a_1) s(a)<f(a1),并且 a 1 a_1 a1 a a a重叠。因为 f ( a 1 ) ≤ f ( a ) f(a_1)≤f(a) f(a1)f(a),如果我们移除 a a a添加 a 1 a_1 a1,可以得到另一个最优解 A ∗ A^* A包含了 a 1 a_1 a1 A ∗ A^* A是最优的,因为 ∣ A ∗ ∣ = ∣ A ∣ |A^*|=|A| A=A

没太看懂。

**定理:**贪心子选择一定产生最优解。

即,证明去掉一个 a 1 a_1 a1之后,对剩下的活动做最早结束时间优先策略,得到的也是子集的最优解。

证明:

  • a 1 a_1 a1是贪心算法选择的活动。
  • S ∗ S^* S是不与 a 1 a_1 a1重叠的活动子集

S ∗ = { a i ∣ i = 2 , . . . , n a n d s i ≥ f ( a 1 ) } S^*=\{a_i | i=2,...,n\ and\ s_i≥f(a_1)\} S={aii=2,...,n and sif(a1)}

  • B B B S ∗ S^* S的最优解。

  • S ∗ S^* S的定义可知, A ∗ = { a 1 } ∪ B A^*=\{a_1\}∪B A={a1}B是可行的,并且是原问题的解。

  • 利用反证法证明 A ∗ A^* A是最优解。

  • 假设 A ∗ A^* A不是最优解,令 A A A是包含 a 1 a_1 a1的最优解,则 ∣ A ∗ ∣ < ∣ A ∣ |A^*|<|A| A<A,且 ∣ A − { a 1 } ∣ > ∣ A ∗ − { a 1 } ∣ = ∣ B ∣ |A-\{a_1\}|>|A^*-\{a_1\}|=|B| A{a1}>A{a1}=B

  • 但是 A − { a 1 } A-\{a_1\} A{a1}也是 S ∗ S^* S的解,与 B B B S ∗ S^* S的最优解矛盾。

  • 所以 A ∗ A^* A一定是原问题的最优解。


image-20230902120102063

image-20230902120113049

Prim算法

  • 连通图的一棵生成树是包含图的所有定点的连通无环子图(一棵树)。
  • 加权连通图的一棵最小生成树是图的一棵权重最小的生成树。

image-20230902120223999

image-20230902120329176

  从某个点出发,首先找和它相邻连接的结点中,权值最小的是谁。是b结点、权值为4,那就把b结点并入进来。接着,再找下一条边,就找和a、b相邻的结点中,权值最小的是哪个边,并且把那个结点并入进来。

  总之,可以视作两个集合:一个是已并入最小生成树的结点集合,另一个是还未并入的结点集合。每次找这两个集合之间权值最小的连接(不能形成环)。

image-20230902120437092


image-20230902120832255

问题:

  一个图,按照这种方式,找出来的所有的最小生成树是不是都是一样的?

  它是一棵树,树的结构是由什么决定的?——我每次的起始点选取不同,它的树根结点不一样,肯定就不一样了。

image-20230902121010752

image-20230902121017904


总结

  贪心策略的选择很重要。

  贪心在某些情况下是可以拿到最优的,但是很容易得到一个局部最优而非全局最优的解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/64015.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch中nn.Conv1d功能介绍

在使用Conv1d函数时&#xff0c;pytorch默认你的数据是一维的&#xff0c;比如一句话“深度学习”可以用一个一维数组 [深, 度, 学, 习] 表示&#xff0c;这个数据就是一维的。图片是二维数据&#xff0c;它有长宽两个维度。 因此在使用 Conv1d 函数时&#xff0c;输入是一个三…

java八股文面试[多线程]——synchronized锁升级详细流程

偏向锁 偏向锁是JDK6中的重要引进&#xff0c;因为HotSpot作者经过研究实践发现&#xff0c;在大多数情况下&#xff0c;锁不仅不存在多线程竞争&#xff0c;而且总是由同一线程多次获得&#xff0c;为了让线程获得锁的代价更低&#xff0c;引进了偏向锁。 偏向锁是在单线程执…

表白墙程序

目录 一、页面代码部分 二、设计程序 二、实现 doPost​编辑 三、实现 doGet 四、前端代码部分 五、使用数据库存储数据 一、页面代码部分 在之前的一篇博客中&#xff0c;已经写过了表白墙的页面代码实现&#xff0c;这里就不再重复了 页面代码如下&#xff1a; <!…

ubuntu22安装和部署Kettle8.2

前提 kettle是纯java编写的etl开源工具&#xff0c;目前kettle7和kettle8都需要java8或者以上才能正常运行。所以运行kettle前先检查java环境是否正确配置&#xff0c;java版本是否是8或者以上。 kettle安装 1、创建kettle目录&#xff0c;并将kettle的zip包解压到kettle目…

linux开启端口

目录 1.查看防火墙状态 1.1 开启防火墙 1.2 再次查看防火墙状态 2.开启指定端口 3. 重启防火墙 4.重新加载防火墙 5.查看已经开启的端口 1.查看防火墙状态 firewall-cmd --state 如果返回的是 not running&#xff0c;那么需要先开启防火墙&#xff0c; 1.1 开启防火…

机器人中的数值优化(五)——信赖域方法

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

写的一款简易的热点词汇记录工具

项目需要对用户提交的附件、文章、搜索框内容等做热词分析。如下图&#xff1a; 公司有大数据团队。本着不麻烦别人就不麻烦别人的原则&#xff0c;写了一款简易的记录工具&#xff0c;原理也简单&#xff0c;手工在业务插入锚点&#xff0c;用分词器分好词&#xff0c;排掉字…

Ansible-playbook循环学习

循环语句简介 我们在编写playbook的时候&#xff0c;不可避免的要执行一些重复性操作&#xff0c;比如指安装软件包&#xff0c;批量创建用户&#xff0c;操作某个目录下的所有文件等。正如我们所说&#xff0c;ansible一门简单的自动化语言&#xff0c;所以流程控制、循环语句…

Ceph入门到精通-LVS基础知识

LB集群: &#xff08;Load Balancing&#xff09;即负载均衡集群,其目的是为了提高访问的并发量及提升服务器的性能&#xff0c;其 实现方式分为硬件方式和软件方式。 硬件实现方式&#xff1a; 常用的有 F5公司的BIG-IP系列、A10公司的AX系列、Citrix公司的 NetScaler系列…

VisualStudio配置pybind11-Python调用C++方法

个人测试下来Debug生成的dll改pyd&#xff0c;py中import会报错gilstate->autoInterpreterState 如果遇到同样问题使用Release吧 目录 1.安装pybind11 1.pip&#xff1a; 2.github&#xff1a; 2.配置VS工程 2.在VC目录中的包含目录添加&#xff1a; 3.在VC目录中的库目录…

【Web系列二十四】使用JPA简化持久层接口开发

目录 环境配置 1、引入依赖 配置文件 代码编写 实体类创建 JPA常用注解 Service与ServiceImpl Service ServiceImpl Controller Dao 三种实现Dao功能方式 1.继承接口&#xff0c;使用默认接口实现 2.根据接口命名规则默认生成实现 3.自定义接口实现(类似MyBatis…

汽车类 ±0.25°C SPI 温度传感器,TMP126EDBVRQ1、TMP126EDCKRQ1、TMP127EDBVRQ1引脚配置图

一、概述 TMP126-Q1 是一款精度为 0.25C 的数字温度传感器 &#xff0c; 支持的环境温度范围为 -55C 至 175C 。TMP126-Q1 具 有 14 位 &#xff08; 有符号 &#xff09; 温度分辨率(0.03125C/LSB)&#xff0c;并且可在 1.62V 至 5.5V 的电源电压范围内工作。TMP126-Q1 具有转…

同创永益入选首批“金融数字韧性与混沌工程实践试点机构”

8月16日下午&#xff0c;由北京国家金融科技认证中心、北京国家金融标准化研究院联合主办的“传递信任 服务发展”金融科技标准认证生态大会在太原成功举办。中国金融电子化集团有限公司党委书记、董事长周逢民&#xff0c;中国科学院院士冯登国&#xff0c;中国工商银行首席技…

Unity 粒子特效遮罩(ParticleMask)

1.需求&#xff1a; 游戏中粒子特效能实现非常好的效果&#xff0c;但是由于粒子特效是独立的系统&#xff0c;Unity自带的Mask普通的遮罩&#xff0c;遮不住粒子特效。 2.实现原理&#xff1a; 通过shader把超出范围的粒子纹理(Texture)&#xff0c;改成透明颜色&#xff0…

Python安装指南(Windows版)

安装python环境 官网下载地址&#xff1a; Download Python | Python.org 我选择3.10.4版本&#xff0c;当然你也可以选择其他版本 安装 安装完成&#xff0c;需要验证是否安装成功。 打开CMD窗口&#xff0c;输入python命令&#xff0c;如果进入如下python窗口则安装成功&…

docker打包vue vite前端项目

打包vue vite 前端项目 1.打包时将测试删除 2.修改配置 3.打包项目 npm run build 显示成功&#xff08;黄的也不知道是啥&#xff09; 打包好的前端文件放入 4.配置 default.conf upstream wms-app {server 你自己的ip加端口 ;server 192.168.xx.xx:8080 ; } server { …

怎样将几个pdf合并?

在日常工作中&#xff0c;我们经常需要处理大量的PDF文件。有时候&#xff0c;我们需要将多个PDF文件合并成一个文件&#xff0c;以便于快速传输或方便查阅。虽然PDF文件本身不能进行编辑&#xff0c;但是借助专业的PDF编辑软件&#xff0c;我们可以轻松地实现将多个PDF文件合并…

推荐两款开源的绘制流程图软件

一句话导读 目前流程图绘制软件非常多&#xff0c;包括本机安装的、web端的都有&#xff0c;如Visio、Graphviz、processOn等等。但是几乎都是收费的。本文给大家介绍两款优秀的开源免费的流程图绘制软件。 目录 一句话导读 一、draw.io 二、Meta2d.js ​1.为什么使用 2.…

4、DVWA——文件包含

文章目录 一、文件包含概述二、low2.1 源码分析2.2 通关分析 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 五、impossible 一、文件包含概述 文件包含是指当服务器开启allow_url_include选项时&#xff0c;就可以通过php的某些特性函数&#xff08;i…

Java“牵手”京东商品详情数据,京东API接口申请指南

京东平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…