贪婪算法最优解问题2

1. 问题

如果硬币的面值是{1, 1*c, 2*c, …, k*c}, 则贪婪算法总是用最少的硬币找零。

如《离散数学及其应用》书中贪婪算法的反例:

有面值1, 10, 25的硬币,找零30。

贪婪算法的解:5c0 + 0c1 + 1c2 =  5*1 + 0*10 + 1*25 = 30,共需6枚硬币

而最优解是:0c0 + 3c1 + 0c2 =  0*1 + 3*10 + 0*25 = 30,只需3枚硬币

但如果补齐中间缺失的硬币面值:{1, 5, 10, 15, 25},

那么贪婪算法的解是 : 1*25 + 1*5 = 30,只需2枚硬币,依然是最优解之一(因为还有15*2也是最优解)

2. 规律

因为最大的25面值的硬币不再满足《贪婪算法最优解问题》问题中的条件,所以无法用该证明方法证明,思路不通时我们先找找满足问题条件的找零方案,看能不能找出一些规律,然后再证明这些规律找出一些推论来间接证明

假设有面值{1, 3, 6, 9}的硬币,当需找零S的最优贪婪算法找零方案:

  1 3 6 9
9       1
10 1     1
11 2     1
12   1   1
13 1 1   1
14 2 1   1
15     1 1
16 1   1 1
17 2   1 1
18       2

从表中可以看出:

1> 除了最大面值和1面值的硬币以外,其他面值的硬币最多只有1个

2> 1面值的硬币最多只有2个

3. 推论证明

3.1 除了最大面值和1面值的硬币以外,其他面值的硬币最多只有1个

最优找零公式:S = m01 + m11c + m22c + … + mkkc

S = m01 + (m11 + m22 + … + mkk)c = m01 + gc  = m0 + gc (m0 < c, g >= 0)

从公式中,我们可以自觉感受到S中,一定有m0个面值为1的硬币,但从严谨的数学逻辑出发,我们还是证明一下

3.2 假设最优找零公式 S = m0 + gc (m0 < c, g >= 0),有另一种最优找零公式 S1 = x + hc (x < c, x != m0, g >= 0)

m0 + gc = x + hc

(m0 - x) = (h-g)c 或(x -m0) = (g-h)c (2个形式的证明都是一样的)

∵x != m0

∴(h-g)c != 0

∴(m0 - x) = nc (n > 0)

∴m0 = nc + x > c (n > 0)

∵m0大于c时,一定可以将c个m0转化为一个面值为c的硬币,转化后的总数量必然小于m0

∴m0 = nc + x不成立,假设不成立

∴最优找零公式S中,一定有m0个面值为1的硬币

3.3 已知S中m0数量固定,所以只要找出S = gc 的最优找零数量,即是S的最优找零方案,我们先尝试找一找各种情况下的方案

S = gc = (m11 + m22 + … + mkk)c

去掉c, g = m11 + m22 + … + mkk

3.3.1 当g <= k时,g = x (x∈{1, 2, …, k}),用一枚面值x的硬币即是最优解

3.3.2 当k< g <= 2k时,g = k + x (x∈{1, 2, …, k}),只需2枚硬币即可,因为1枚硬币最多只能表达到k的面值,而g > k,所以g = g = k + x即是最优解

3.3.3 当2k< g <= 3k时,g = 2k + x (x∈{1, 2, …, k}),只需3枚硬币即可,因为用2枚硬币最多只能表达到2k的面值,而g > 2k,所以g = 2k + x即是最优解

也就是说,对于任意一个g,总是可以表达为 g = nk + x 这种形式(如我们所有的数都可以用 (n10 + x)(0<= n, 0< x < 10)来表示),且这种形式的找零方案是最优的(使用n + 1枚硬币)

3.4 证明,g = m11 + m22 + … + mkk = nk + x (0 < x < k) 时,没有一种其他的找零方案使用的硬币数 <= n

反证,假设有一种找零方案g1 = m11 + m22 + … + mkk,使用的硬币数 <= n

∵n枚kc面值的的硬币总数总是大于或等于n枚由{1c, 2c, …, kc}组成的硬币总数

∴g1 <= nk < nk + x = g

∴g1 != g

∴不存在这一的找零方案g1

∴g = nk + x这样的找零方案总是最优的

∴g总是用最大数量的k,和一枚其他数量的x去找零,这完全满足贪婪算法的找零方案

∴S = gc 的最优找零数量是贪婪算法

∴S = m0 + gc 的最优找零方案是贪婪算法

时间: 2024-10-11 05:55:48

贪婪算法最优解问题2的相关文章

贪婪算法_找零钱

贪婪算法是一种求近似解的方法,它存在如下几个问题: 1.不能保证最后的解是最优解. 2.不能求最大解或者最小解问题. 3.只能满足某些约束条件的可行解范围. 下面给出用贪婪算法解决找零钱这一问题的代码: 1 #include<stdio.h> 2 #define max 7 3 float facevalue[max]={50,20,10,5,1,0.5,0.1};//同时是否有无该面值用于找零,也能在此处进行修改 4 int num[max]={0}; 5 float exchange(fl

knapsack problem 背包问题 贪婪算法GA

knapsack problem 背包问题贪婪算法GA 给点n个物品,第j个物品的重量,价值,背包的容量为.应选哪些物品放入包内使物品总价值最大? 规划模型 max s.t. 贪婪算法(GA) 1.按价值密度从大到小依次放入包内直到放不下,设此时放了s个物品 2.将所得价值与最大价值()所比较,取最大的作为输出 贪婪算法与最优解竞争比(近似比)为 证明:

数据结构域算法系列之二 贪婪算法和人生规划

前几天和苯螃蟹聊天,谈到对未来的规划.螃蟹说自己要在5年以后做到像某大牛那样熟知一切专业知识并且做到写文章信手拈来.说完自己的,就来问我"5年内的职业规划是什么?"我其实是那种平时想事情根本不过脑子的人,怎么会整天没事琢磨5年规划?于是我老实告诉她:"我没有5年规划,我觉得只要做好自己遇到的每一件事,就自然能够通向最好的结果." 苯螃蟹听了以后大惊:"你怎么能够没有规划呢?!" 难怪苯螃蟹会惊讶万分.因为是我告诉了她读者文摘上那个关于怎样规划自己

动态规划与贪婪算法

观点描述来源与博客:http://blog.csdn.net/woaimeinuo/article/details/45651163 贪婪:每一次都选择当前最好的,虽然不是全局最优解,但其可以让你找到局部最优解或是次优解.其实,有次优解也不错了.贪婪算法基本上是一种急功近利的算法,但是并不代表这种算法不好,如果贪婪的是一种长远和持续,又未尝不可呢? 动态规划: 对于大部分的问题,贪婪法通常都不能找出最优解,因为他们一般没有测试所有可能的解.因为贪婪算法是一种短视的行为,只会跟据当前的形式做判断,

《算法图解》——第八章 贪婪算法

第八章    贪婪算法 1 简单的贪婪算法 每步都采取最优的做法,每步都选择局部最优解. 2 背包问题 有些情况下,完美是优秀的敌人.如果你只需要找到一个大致解决问题的算法,贪婪算法挺不错,因为实现容易,结果与正确结果相当接近. 练习8.1 你在一家家具公司工作,需要将家具发往全国各地,为此你需要将箱子装上卡车.每个箱子的尺寸各不相同,你需要尽可能利用每辆卡车的空间,为此你将如何选择要装上卡车的箱子呢?请设计一种贪婪算法.使用这种算法能得到最优解吗? 选择可以装入卡车中最大的箱子,不断重复,直到

《算法图解》第八章_贪婪算法_集合覆盖问题

一.贪婪算法介绍 算法基本思路:从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解.每一步只考虑一个数据,他的选取应该满足局部优化的条件.若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止.(摘自 贪婪算法_百度百科) 简单直接的描述,就是指每步都选择局部最优解,最终得到的就是全局最优解. 二.引入:集合覆盖问题 假设你办了个广播节目,要让全美个州的听众都收听得到,为此,你需要决定在哪些广

Python贪婪算法

贪婪算法 每步均选择局部的最优解,重复此过程,最终即得到全局的最优解 简而言之就是每步都采用最优解 优点: 简单易行 缺点: 并非在所有情况下都奏效 经典的问题: 背包问题 集合覆盖问题 贪婪算法下的近似算法解决集合覆盖问题 states_needed = set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az&

贪婪算法回顾

回顾 还记的贪婪算法么? 如果你不记得了, 看了下面这个例子你一定会想起来, 因为这个例子太普遍了, 几乎每个将贪婪算法的地方, 第一个例子都是它, 言归正传. 问题: 现在有如下课程表, 要将这些课尽可能多的安排在教室A内. 课程名 开始时间 结束时间 语文课 9:00 10:00 数学课 9:30 10:30 音乐课 10:00 11:00 政治课 10:30 11:30 美术课 11:00 12:00 首先将所有课程都安排在教师A是不现实的, 因为时间上存在冲突. 那改怎么安排呢? 这个问

矩阵相乘求最优解(C++算法)

#include "stdafx.h"  #include <iostream>   using namespace std;     const int L = 7;    int RecurMatrixChain(int i,int j,int **s,int *p);//递归求最优解  void Traceback(int i,int j,int **s);//构造最优解    int main()  {      int p[L]={30,35,15,5,10,20