贪心算法
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
6.贪心方法模型
a.工程计划模型 b.部分背包与每步最优 c.构造贪心算法
a.工程计划模型
我们常常碰到这样的问题:完成一个工程需
要若干个步骤,每个步骤都有若干种方法, 图示—— 步骤a 步骤b 步骤c ... 步骤n 方法b1 方法c1 方法a1 方法b2 方法c2 方法n1 方法a2 方法b3 方法c3 方法c4
种树问题:一条街道分为n个区域(按1-n编号), 每个都可种一棵树。有m户居民,每户会要求在区 域i-j区间内种至少一棵树。现求一个能满足所有要 求且种树最少的方案。 算法构造: 1.对于要求,以区间右端(升序)为首要关键字, 左端(升序)为次要关键字排序。 2.按排好的序依次考察这些要求,若未满足,则在 其最右端的区域种树,这时可能会满足多个要求。 证明思路:解法并不唯一,关键是证明没有比该解 法更好的解法。按步骤1排序之后,会发现对于每 个要求,在最右边的区域内种树所得的结果总不会 差于在其他区域种树。至于为什么这样排序,留给 你——读者们思考吧。
每个方法有一个权值(如效率、质量),其大小往 往和其他步骤中选取的方法有关。有些时候权值无 意义,表示方法不可选择。要求给出一个方法组合, 是权值和最大。 在这里,暂且把它称作“工程计划”。很多实际问 题都可以归纳为这个模型。 对于不同形式的工程计划,我们有不同的解法。 若权值与整个过程或前后步骤的方法选择都有关, 我们使用搜索算法——时间复杂度高得吓人。 若每个权值只与上(或下)一步或少数几步的方法 选择都有关,我们使用动态规划——有比较高的效 率,在下一章会讲到。 若每个权值与其他步骤的方法选择都没有关系,我 们使用贪心方法。
算法分析:设a[i]为第I堆纸牌的张数(0<=I<=n), v为均分后每堆纸牌的张数,s为最小移动次数。 我们用贪心算法,按照从左到右的顺序移动纸牌。 如第I堆的纸牌数不等于平均值,则移动一次(即s 加1),分两种情况移动: 1.若a[i]>v,则将a[i]-v张从第I堆移动到第I+1堆; 2.若a[i]<v,则将v-a[i]张从第I+1堆移动到第I堆。 为了设计的方便,我们把这两种情况统一看作是将 a[i]-v从第I堆移动到第I+1堆,移动后有a[i]=v; a[I+1]=a[I+1]+a[i]-v. 在从第I+1堆取出纸牌补充第I堆的过程中可能回出 现第I+1堆的纸牌小于零的情况。
问题:有N件物品和一个最大载重为M的背包,每 件物品都有相应的重量和价值。现要求给出一个存 放方案,使背包中物品总价值最大。部分背包要求, 每件物品都可只装入它的一部分(部分重量有成比 例的部分价值)。所涉及到的数字均为整数。 (注:有时该问题表述为体积形式,即背包体积有 限,每件物品有体积和价值。在本系列我选择表述 为重量形式。) 思路:背包中物品总价值最高,即单位重量物品价 值最高。显然,应该多装单位重量价值高的物品。 这样,我们先装入单位重量价值最高的物品,再装 入第二高的……直到重量达到M(有必要时最后一 件物品只装一部分),已达到物品总价值最高。该 算法时间复杂度O(n),效率很高;而且实现很容易。 这些是贪心法最大的特点。
int total = 100,value = 33,change = 0,complete = 0,left = 0,cur_change = 0; while(!complete) { left = total – value – change; if(left <= 0 ) complete = 1; else { if(left>=25) cur_change = 25; eles if (left>=10) cur_change = 10; else if (left>=5) cur_change = 5; else if(left>=1) cur_change = 1; } if(!change) { change = change+cur_change; printf(― %d‖,cur_change); } }
很多竞赛题看似可以用贪心法,其实贪心法得不到 最优解,原因是每一步的选择对其他步骤有影响。 数字三角形问题:有一个数字三角形(如下图)。 现有一只蚂蚁从顶层开始向下走,每走下一级时, 可向左下方向或右下方向走。求走到底层后它所经 过的数的最大值。 1 63 826 2165 32476
假设需要找给小孩6 7美分,首先入选的是两枚2 5美分的硬 币,第三枚入选的不能是2 5美分的硬币,否则硬币的选择 将不可行(零钱总数超过6 7美分),第三枚应选择1 0美分 的硬币,然后是5美分的,最后加入两个1美分的硬币。 贪婪算法有种直觉的倾向,在找零钱时,直觉告诉我们应使 找出的硬币数目最少(至少是接近最少的数目)。可以证明 采用上述贪婪算法找零钱时所用的硬币数目的确最少
如果用贪心法,每次向最大的方向走,得到
结果为1+6+8+2+3=20。可是明明还有另一 条路,1+3+6+6+7=23。 问题出在哪?每次的选择对后面的步骤会有 影响!第三级选了8,就选不到第四、五级较 大的数了。 这个问题正确的解法会在下一章介绍。 有一个很实用的小技巧:竞赛题会给出数据 规模。通过数据规模,我们可以大致判断该 用何种算法。贪心算法可承受的数据规模很 大,一般都会上万。如果给出的数据规模是 100或1000,优先考虑动态规划吧
2、局部最优解: 由于运用贪心策略解题在每一次都取得了最优 解,但能够保证局部最优解得不一定是贪心算法。 如大家所熟悉得动态规划算法就可以满足局部最优 解, 在遇到具体问题时,许多选手往往分不清哪些 题该用贪心策略求解,哪些题该用动态规划法求解。 在此,我们对两种解题策略进行比较。
三、贪心和动态规划比较
贪心算法
1、 贪心策略的定义
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做 出在当前看来是最好的选择。也就是说,不从整体最优上加 以考虑,他所做出的仅是在某种意义上的局部最优解。贪心 算法不是对所有问题都能得到整体最优解,但对范围相当广 泛的许多问题他能产生4;一词我们便可以看出,贪心策略总 是做出在当前看来是最优的选择,也就是说贪心策略并不是 从整体上加以考虑,它所做出的选择只是在某种意义上的局 部最优解,而许多问题自身的特性决定了该题运用贪心策略 可以得到最优解或较优解
while
5、应用举例
5-1 [找零钱] 一个小孩买了价值少于1美元的糖,并将1美元的钱交给售货员。售
货员希望用数目最少的硬币找给小孩。假设提供了数目不限的面值为2 5美分、1 0美分、5美分、及1美分的硬币。售货员分步骤组成要找的零钱数,每次加入一 个Байду номын сангаас币。选择硬币时所采用的贪婪准则如下:每一次选择应使零钱数尽量增大。 为保证解法的可行性(即:所给的零钱等于要找的零钱数),所选择的硬币不应 使零钱总数超过最终所需的数目。
二、贪心算法的特点
贪心算法有什么样的特点呢?
适用于贪心算法解决的问题应具有以下特点:
1、贪心选择性质:
所谓贪心选择性质是指应用同一规则f, 将原问题变为一个相似的、但规模更小的子 问题、而后的每一步都是当前看似最佳的选 择。这种选择依赖于已做出的选择,但不依 赖于未做出的选择。从全局来看,运用贪心 策略解决的问题在程序的运行过程中无回溯 过程。
b.部分背包与每步最优
强调:每个权值与其他步骤的方法选择都没有关系。 这样每步最优就可以得到全局最优——每一步都取 最大的权值就可以了。 换而言之,贪心算法要求,局部的贪心选择,可以 组成全局的最优解。 在实际问题中,这是需要证明的。如果这个无法证 明,贪心算法所得的解不是最优解,一般只是较优 解(较优解可为搜索剪枝提供方便)。 下面是贪心算法最经典的例子:部分背包问题。 (下一章会讲到另外两种背包问题。)
利用贪心算法解题,需要解决两个问题: 一是问题是否适合用贪心法求解。我们看一个找币 的例子,如果一个货币系统有三种币值,面值分别 为一角、五分和一分,求最小找币数时,可以用贪 心法求解;如果将这三种币值改为一角一分、五分 和一分,就不能使用贪心法求解。用贪心法解题很 方便,但它的适用范围很小,判断一个问题是否适 合用贪心法求解,目前还没有一个通用的方法,在 信息学竞赛中,需要凭个人的经验来判断。 二是确定了可以用贪心算法之后,如何选择一个贪 心标准,才能保证得到问题的最优解。在选择贪心 标准时,我们要对所选的贪心标准进行验证才能使 用,不要被表面上看似正确的贪心标准所迷惑,如 下面的例子
[均分纸牌]有N堆纸牌,编号分别为1,2,…,n。 每堆上有若干张,但纸牌总数必为n的倍数.可以在任 一堆上取若干张纸牌,然后移动。移牌的规则为:在 编号为1上取的纸牌,只能移到编号为2的堆上;在 编号为n的堆上取的纸牌,只能移到编号为n-1的堆 上;其他堆上取的纸牌,可以移到相邻左边或右边 的堆上。现在要求找出一种移动方法,用最少的移 动次数使每堆上纸牌数都一样多。例如:n=4,4堆 纸牌分别为:① 9 ② 8 ③ 17 ④ 6 移动三次可以达 到目的:从③取4张牌放到④ 再从③区3张放到②然 后从②去1张放到①。 输入输出样例:4 9 8 17 6 屏幕显示:3
四、贪心算法的基本思路如下:
1.建立数学模型来描述问题。 2.把求解的问题分成若干个子问题。 3.对每个子问题求解,得到每个子问题的局
部最优解。 4.把每个子问题的局部最优解合成为原来问 题的一个解。
4.1实现该算法的过程:
从问题的某一初始状态出发;
能朝给定总目标前进一步 do 求出可行解的一个解元素; 由所有解元素组合成问题的一个可行解;
如n=3,三堆指派数为1
2 27 ,这时v=10, 为了使第一堆为10,要从第二堆移9张到第一 堆,而第二堆只有2张可以移,这是不是意味 着刚才使用贪心法是错误的呢? 我们继续按规则分析移牌过程,从第二堆移 出9张到第一堆后,第一堆有10张,第二堆剩 下-7张,在从第三堆移动17张到第二堆,刚 好三堆纸牌都是10,最后结果是对的,我们 在移动过程中,只是改变了移动的顺序,而 移动次数不便,因此此题使用贪心法可行的。
c.构造贪心算法
构造与证明是贪心算法的难点,常常要求我
们要有敏锐的观察力、多角度思考的变通能 力、丰富的数学知识和推理能力。 下面举几个贪心算法的例子,供大家揣摩、 掌握规律。
删数问题:给出一个N位的十进制高精度数,要求 从中删掉S个数字(其余数字相对位置不得改变), 使剩余数字组成的数最小。 算法构造: 1.每次找出最靠前的这样的一对数字——两个数字 紧邻,且前面的数字大于后面的。删除这对数字中 靠前的一个。 2.重复步骤1,直至删去了S个数字或找不到这样的 一对数。 3.若还未删够S个数字,则舍弃末尾的部分数字,取 前N-S个。 证明思路:显然,在只删一个数字时,唯有步骤1 的方法能使数变小;可推理得出,删多个数字时, 所有最优的方法都可看做是对步骤1的重复。也就 是说,以上方法是最优策略之一。
工序问题:n件物品,每件需依次在A、B机床上加工。已知 第i件在A、B所需加工时间分别为A[i]、B[i],设计一加工顺 序,使所需加工总时间最短。 算法构造: 1.设置集合F、M、S:先加工F中的,再加工M中的,最后 加工S中的。 2.对第i件,若A[i]>B[i],则归入S;若A[i]=B[i],则归入M。 3.对F中的元素按A[i]升序排列,S中的按B[i]降序排列。 证明思路: 1.F中的能“拉开”A、B加工同一件工件的结束时刻,为后 面的工件加工“拉开时间差”,利于节省总时间。S中的刚 好相反。因而,F中元素放在最前一定是最优策略之一。 2.F中A[i]小的前置,可以缩短开始时B的空闲时间,但会使F 所有工件“拉开的时间差”缩短。不过可以证明,后者带来 的损失不大于前者获得的优势。对称地,对S也一样。因而 步骤3是可行的。