贪心算法

Posted 中学生编程与信息学竞赛自学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心算法相关的知识,希望对你有一定的参考价值。

本课程是从少年编程网转载的课程,目标是向中学生详细介绍计算机比赛涉及的编程语言,数据结构和算法。编程学习最好使用计算机,请登陆 www.3dian14.org (免费注册,免费学习)。


本节课我们继续探讨如何使用贪心算法来解决问题。今天我们讲述埃及分数的问题。


问题描述


如果一个分数的分子为1且分母为正整数,则该分数称为单位分数,例如1/3为单位分数。 每个小于1的正分数都可以表示为单位分数的总和,这种表现形式被称为埃及分数,因为它被古埃及人使用。

贪心算法(2)

今天的问题就是:如何运用贪心算法生成一个正分数的埃及分数表示?


贪心算法(2)

问题分析


对于给定一个小于1的正分数 f ,假设它的形式是 n/d,其中d>n, d,n 是正整数。


我们知道如果f>=1/k, 那么它一定可以包含一个单位分数1/k,这里k是大于1的整数。


在应用贪心算法时,我们总是先为分数 f 寻找小于或等于f的最大的单位分数,从中减去找到的单位分数,然后把差作为新的分数,再去寻找新分数的最大的单位分数,这样继续下去,直到最后剩下是单位分数为止。把这些找到的单位分数加起来,就是原分数 f 的埃及分数表示。


那么如何找小于或等于 f 的最大单位分数呢? 


浮现于脑海中的第一种方法很简单,从1/2开始,依次把1/2,1/3,1/4,......等单位分数与分数 f 比较,一定可以找到第一个小于或等于 f 的单位分数。


请看下面的示意图。

贪心算法(2)


但是这个看似简单的算法实现起来可能会有些麻烦:在计算机中,分数一般需要用浮点数表示,而浮点数比较大小的时候会有误差。


贪心算法(2)

算法分析


其实有更加简便的方法。我们举例来说明。


考虑6/14,它的倒数是14/6, 我们只要找到不小于14/6的最小正整数,得到3,那么3的倒数——1/3就是当前要找的最大单位分数。

请你想想为什么?


接下来 6/14 减去1/3 得到  4/42,它还不是单位分数,考虑它的倒数是42/4, 不小于42/4的最小整数是11,而11的倒数1/11,就是是我们要找的第二个单位分数。


最后4/42减去1/11得到1/231,找到了最后一个单位分数。因此 6/14的埃及分数形式就是1/3+1/11+1/231。


假设有一个分数f = n/d, 其中d>n, d 和 n是正整数,过程getEF(n,d)用于求f的埃及分数表示形式。


贪心算法(2)


注意在getEF(n,d)过程中有递归调用部分:getEF(n%d,d)以及getEF(n*m-d,d*m)。


贪心算法(2)



这两个分支是求不大于n/d的最大单位分数。它可以对应下面的公式:



代码实现


下面是用贪心算法找埃及分数表示形式的C++代码实现。


#include <iostream> 

using namespace std; 


void getEF(int n, int d) 

// 如果分子分母中有一个是0,返回 

if (d == 0 || n == 0) 

return; 


//如果分子可以被分母整除,那么给的数就是整数,不是分数 

if (n % d == 0) 

cout << n/d ; 

return; 


// 如果分子大于分母,变成带分数的形式, 继续对分数部分求埃及分数形

              

if (n > d) 

cout << n/d << " + "; //输出整数部分 

getEF(n % d, d);  //对分数部分继续求埃及分数形式 

return; 


    //找出比不小于d/n的最小整数m

    int m;

//如果分母n可以被分子整除,那么埃及分数形式就很简单,就是商的倒数

if (d % n  == 0) 

m = d/n;

cout << "1/" << m; 

    else //如果分母不可以被分子整除

{

m = d/n + 1;

                

    //它的倒数就是找到的第一个埃及分数

cout << "1/" << m << " + "; 


//对剩余部分采用递归调用的方式继续寻找埃及分数 

getEF(n * m - d, d * m); 

}



int main() 

int n = 6, d = 14; 

cout << "The Egyptian fraction format of "

<< n << "/" << d << " is\n "; 

getEF(n, d); 

return 0; 

}







以上是关于贪心算法的主要内容,如果未能解决你的问题,请参考以下文章

程序员算法基础——贪心算法

贪心思想

算法基础--贪心算法

贪心算法学习,附由贪心算法引发的人生感悟。

算法贪心算法(0-1背包问题)

python常用算法——贪心算法,欧几里得算法