【算法-贪心算法-1】

贪心法:把一个复杂问题分解为一系列较为简单的局部最优选择,每一步选择都是对当前解得一个扩展,直到获得问题的完整解。
通过一个问题来引入:
【货币兑付问题】
要求用最少的货币张数来支付现金。
给定的现金p是约束条件
最少的货币张数是目标函数
满足约束函数的向量称为问题的可行解
满足目标函数的向量称为问题的最优解

如何用贪心法来解这个问题呢?
计算问题的每一步都是作出当前看来最好的选择。
例:现金p为57.8元
先拿出1张50元,再拿出1张5元,再拿出2张一元,拿出1张五毛,1张两毛,一张1毛。
每一步都尽量拿最大面值的最多张。

例题【1】活动安排问题
在给出的活动集合中选出最大的相容活动子集合。

template<class Type>
void GreedySelector(int n, Type s[], Type f[], bool A[])// 各活动的起始时间和结束时间存储于数组s和f中且按结束时间的非减序排列 
{
       A[1]=true;//第一个结束的活动被选择 
       int j=1;
       for (int i=2;i<=n;i++) {
          if (s[i]>=f[j]) {//活动相容的条件 
		   A[i]=true;
		   j=i;//选择下一个结束最早的活动,并移动j,j代表当前选择活动的结束时间 
		    }
          else A[i]=false;//A[i]=true表示可以选择该活动,false则表示不能选择有冲突 

该算法每次总是选择具有最早完成时间的活动以此来剩下最多的时间。
算法复杂度O(n)
值得注意的是,贪心算法并不总能求得问题的整体最优解,大概只能求得最优解的近似解,但对于活动安排问题则能求得整体最优解,可以通过数学归纳法来求证。

那怎么知道一个问题能否用贪心算法求解呢?
【贪心算法的基本要素】
1.贪心选择性质
所求问题的整体最优解可以通过一系列局部最优的选择来达到
如何证明贪心选择性质?
(1)首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始。做了贪心选择后,原问题简化为规模更小的类似子问题
(2)然后,用数学归纳法证明,通过每一步做贪心选择,最终可得到问题的整体最优解
2.最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质

已知动态规划算法也要求最优子结构性质,那具有这个性质的问题应该用贪心法还是动态规划算法呢?
例题【2】背包问题
问题概念:给定n个物体的重量和价值,给定一个包的承载重量,要求尽可能装入价值最高的物品。
用贪心法求解

void Knapsack(int n,float M,float v[],float w[],float x[])
{ //v[]:物品的价值;w[]:物品的重量;x[]:物品的装包重量
       Sort(n,v,w);      //按单价对物品排序(由大到小)
       int i;
       for (i=1;i<=n;i++)
	    x[i]=0;
       float c=M;         //M:包的容量(承重量),c:包的剩余容量
       for (i=1;i<=n;i++) {
          if (w[i]>c) break;//装不下了 
          x[i]=1;//装入一整个 
          c-=w[i];//调整剩余容量 
          }
       if (i<=n)  
	   x[i]=c/w[i];//最后一个无法全部装进入,装入一部分 
}

选择的标准是物体的单位质量价值,因此0-1背包问题无法用贪心法求解,最后剩余的空间会稀释单位背包空间价值

例题【3】最优装载问题
问题概念:给定一个轮船载重量c,给定一批集装箱重量w[i],要求尽可能多的集装箱装上船。
选择标准:重量最轻者先装。

template<class Type>
void Loading(int x[],Type w[],Type c,int n)//x数组表示有没有装入,w数组重量,c容量,n物体数量 
{
int *t = new int [n+1];//t数组存放物体重量排序后的结果 
Sort(w, t, n);   //对集装箱的重量w按由小到大排序,w的下标存于t中
for (int i = 1; i <= n; i++) x[i] = 0;//初始化0 
for (int i = 1; i <= n && w[t[i]] <= c; i++) //选择重量最小的集装箱装入 
     {x[t[i]] = 1; c -= w[t[i]];}
}

可以证明最优装载问题具有贪心选择性质


上图说了这么多,意思就是既然存在一个没有选择当前我们有的最轻物体a的最优解,那么我们可以把最优解中的最轻物体b换成当前我们有的最轻物体a,这当然是可行的,因此a一定比b要轻,因此可以证明存在贪心选择性质。

可以证明最优装载问题具有最优子结构性质
在这里插入图片描述
该算法复杂度O(nlogn),主要计算量在于将集装箱从小到大排序。

定理4.2 对装载问题任何规模为k 的输入,算法得到最优解.
证明法 对问题规模归纳. 设集装箱从轻到重记为1, 2, … , k.
证: k=1, 只有1个箱子,算法显然正确.
假设对于 k 个集装箱的输入,贪心法都可以得到最优解,考虑 输入 N = {1, 2, … , k+1}, 其中 w1 < =w2<= … <=wk+1.
由归纳假设,对于N’ = {2,3,…,k+1},C’ = C-w1, 贪心法 得到最优解 I ’. 令 I = {1}U I’,则 I (算法解)是关于 N 的最优解.
若不然,存在包含 1 的关于 N 的最优解 I*(如果 I* 中没有1,用 1 替换 I* 中的第一个元素得到的解也是最优解),且| I*| > | I |; 那么 I* - {1}是关于 N’ 和C’的解且
| I*-{1}| > | I - {1} | = | I’|
与 I’ 的最优性矛盾.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值