1 / 117

贪婪算法

贪婪算法. 贪婪算法. 1 贪婪算法的思想 2 可绝对贪婪问题 3 相对贪婪问题 4 问题的复杂性 5 贪婪算法实例. 1 贪婪算法的思想. 例:求方法使生产某产品所花费的时间最少;. 贪婪算法 ( 贪心算法 ) 的根本思想:. 最直接的方法:枚举;. 高效一点的方法:在生产该产品的每一道工序上都选择最省时的方法;. 以逐步的局部最优,达到最终的全局最优。. 贪婪算法通过一系列的局部选择来得到一个问题的解。所作的每一个选择都是当前状态下“最优”的选择。. 如何判断“当前最优”?. 要依照某种策略。策略“只顾眼前,不管将来”,称之为“贪婪策略”。.

fineen
Download Presentation

贪婪算法

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 贪婪算法

  2. 贪婪算法 • 1 贪婪算法的思想 • 2 可绝对贪婪问题 • 3 相对贪婪问题 • 4 问题的复杂性 • 5 贪婪算法实例

  3. 1 贪婪算法的思想 • 例:求方法使生产某产品所花费的时间最少; • 贪婪算法(贪心算法)的根本思想: • 最直接的方法:枚举; • 高效一点的方法:在生产该产品的每一道工序上都选择最省时的方法; • 以逐步的局部最优,达到最终的全局最优。 • 贪婪算法通过一系列的局部选择来得到一个问题的解。所作的每一个选择都是当前状态下“最优”的选择。 • 如何判断“当前最优”? • 要依照某种策略。策略“只顾眼前,不管将来”,称之为“贪婪策略”。 • 贪婪算法没有固定的算法框架,算法设计的关键是贪婪策略的选择。 • 贪婪算法能否得到最优解?

  4. 1 贪婪算法的思想-例4.1-问题分析 • 例4.1 币种统计问题 • 某单位给每个职工发工资(精确到元)。为了保证不要临时兑换零钱,且取款的张数最少,取工资前要统计出所有职工的工资所需各种币值(100,50,20,10,5,2,1元共七种)的张数。请编程完成。

  5. 1 贪婪算法的思想-例4.1-算法设计 • 将七种币值存储在数组B。这样,七种币值就可表示为B[i],i=1,2,3,4,5,6,7。为了能实现贪婪策略,七种币应该从大面额的币种到小面额的币种依次存储。 • 数据结构 • 记录最终币值所需数量:设置一个有7个元素的累加器数组S。 • 若是同时处理多个人的工资(GZ),则最好从数据库或文件读入GZ数据,再处理。本算法每次运行处理n个人的工资,从键盘输入GZ数额。 • 贪婪策略: • 对每个人的工资,用“贪婪”的思想,先尽量多地取大面额的币种,由大面额到小面额币种逐渐统计。

  6. 1 贪婪算法的思想-例4.1-算法实现 main( ){ int i,j,n,GZ,A; int B[8]={0,100,50,20,10,5,2,1},S[8]; input(n); S[8]={0,0,0,0,0,0,0,0}; for(i=1;i<=n;i++){ input(GZ); for(j=1,j<=7;j++) { A=GZ/B[j]; S[j]=S[j]+A; GZ=GZ-A*B[j]; } } for(i=1;i<=7;i++) print(B[i], “----”, S[i]); } • 代码只需完全实现算法; 能否得到最优解由算法决定。 时间复杂度? • 嵌套的1->7循环与问题规模无关; • O(n)。

  7. 1 贪婪算法的思想-例4.1-不同情况 • 什么样的问题可以使用贪婪算法策略,并获得最优解? • 某国的币种是这样的,共9种:100,70,50,20,10,7,5,2,1。 • 这种情况下,刚才的贪婪算法是否能够求得最优解? • 在这样的币值种类下,再用贪婪算法就行不通了,比如某人工资是140,按贪婪算法140=100*(1张)+20*(2张)共需要3张,而事实上,只要取2张70面额的是最佳结果,这类问题可以考虑用动态规划算法来解决。 为什么? • 因为,7、70破坏了“取最优”的贪婪策略的正确性。 又为什么?

  8. 1 贪婪算法的思想-例4.2 活动安排问题 • n个活动E={1,2,..,n},都要求使用同一公共资源(如演讲会场等)。且在同一时间仅一个活动可使用该资源。 i[si,fi), si为起始时间, fi为结束时间。si<fi 活动i和j相容: si>=fj或sj > =fi • 活动安排问题:求最大的相容活动子集合。 ---尽可能多的活动兼容使用公共资源。 Sj fj Si fi Si fi Sj fj

  9. 1 贪婪算法的思想-例4.2 活动安排问题-算法 1.按结束时间非减序排序:f1<=f2 <= .. <= fn --O(nlogn) 2.从第1个活动开始,按顺序放进集合A。放入活动i当且仅当与集合A中已有元素相容。 --与集合A中最后元素j比较:若si> =fj则加入,否则不加入 fj=max k  A(fk)---集合A中的最大结束时间 E={a,b,c,d,e,f} A={a,b,d,f} Si fi S1 f1 S2 f2 S4 f4 S6 f6 S3 f3 S5 f5

  10. void GreedySelector(int n, int s[], int f[],bool A[]) • { A[1]=true;// A[i]=true表示已被放入集合 • int j=1; • for (int i = 2; i <=n; i++) -O(n) • { if (s[i]>=f[j]) • { A[i]=true; • j=i; • } • else A[i]=false; • } • } 各活动的起始时间和结束时间存储于数组s和f中且按结束时间的非减序排列 当输入的活动已按结束时间的非减序排列,算法只需O(n)时间安排n 个活动,使最多的活动能相容地使用公共资源。 如果所给出的活动未按非减序排列,可以用O(nlogn)的时间重排。

  11. 1 贪婪算法的思想-例4.2 活动安排问题 • 规则:选择具有最早结束时间的相容活动加入,使剩余的可安排时间最大,以安排尽可能多的活动。 • 由于输入的活动以其完成时间的非减序排列,所以算法GreedySelector每次总是选择具有最早完成时间的相容活动加入集合A中。直观上,按这种方法选择相容活动为未安排活动留下尽可能多的时间。 • 也就是说,该算法的贪心选择的意义是使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。

  12. 1 贪婪算法的思想-例4.2 活动安排问题 例:设待安排的11个活动的开始时间和结束时间按结束时间的非减序排列如下:

  13. 例4.2 活动安排问题 算法GreedySelector的计算过程如左图所示。图中每行相应于算法的一次迭代。阴影长条表示的活动是已选入集合A的活动,而空白长条表示的活动是当前正在检查相容性的活动。

  14. 1 贪婪算法的思想-例4.2 活动安排问题 若被检查的活动i的开始时间Si小于最近选择的活动j的结束时间fi,则不选择活动i,否则选择活动i加入集合A中。 贪心算法并不总能求得问题的整体最优解。但对于活动安排问题,贪心算法GreedySelector却总能求得的整体最优解,即它最终所确定的相容活动集合A的规模最大。这个结论可以证明。

  15. 贪心算法GreedySelector—总能得到整体最优解,即A规模最大。贪心算法GreedySelector—总能得到整体最优解,即A规模最大。 • 证明: n个活动E={1,2,..,n},按结束时间非减序排序:f1<=f2 <= .. <= fn。 1.总存在一个最优解以贪心选择开始即包含活动1。 E按结束时间非减序排序,活动1具有最早结束时间。 设A为最优解,AE,A也按结束时间非减序排序。 设A中第一活动为k,k=1时,显然成立。 k>1时,设B=A-{k}{1},由于f1 <=fk,且A中活动互为相容,则B中活动也互为相容。 而B与A中活动个数相同,且A为最优解,则B为最优解。

  16. 2.选择活动1以后,问题变为子问题E’:与活动1相容的活动安排问题。2.选择活动1以后,问题变为子问题E’:与活动1相容的活动安排问题。 设A为包含活动1的最优解,则A’=A-{1}为E’的一个最优解。 假如存在E’的一个解B’,|B’|>|A’|,则|B’ {1}|>A,与A为最优解矛盾。 由1,2 可知GreedySelector—总能得到整体最优解。

  17. 1 贪婪算法的思想-获得最优解的条件 • 对于一个具体的问题,怎样知道是否可用贪心算法解此问题,以及能否得到问题的最优解呢? • 这个问题很难给予肯定的回答。 • 从许多可以用贪心算法求解的问题中看到这类问题一般具有2个重要的性质:贪心选择性质和最优子结构性质。

  18. 1 贪婪算法的思想-获得最优解的条件 • 贪婪选择性质 • 指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。 • 贪心算法通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。 • 最优子结构性质 • 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。

  19. 1 贪婪算法的思想-获得最优解的条件 不具有最优子结构例子: 如图,有4个点,分别是A、B、C、D,相邻两点用两条连线C2k,C2k-1(1≤k≤3)表示两条通行的道路。连线上方的数字表示道路长度。定义从A到D所有路径中,长度除以4所得余数最小的路径为最优路径。求一条最优路径。 在本题中,如果按照最优子结构的思维来求解就会发生错误。例如,A最优取值可以由B的最优取值来确定,而B的最优取值为0,所以A的最优值为2,而实际上,路径C1—C3—C5可得最优值为0,所以,B的最优路径并不是A最优路径的子路径,也就是说,A的最优取值不是由B的最优取值决定的,其不具有最优子结构。

  20. 1 贪婪算法的思想-总结 • 适用问题 • 两类 • 可绝对贪婪问题 • 求最优解; • 具有贪婪选择性质、最优子结构性质; • 相对贪婪问题 • 求近似解; • 不具备全部性质,但求解效率要求高,解的精度要求不高。 得到近似解不算彻底解决问题。 • 算法框架 • 核心:贪婪策略

  21. 2 可绝对贪婪问题-例4.3 • 例4.3 键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。 • 输出应包括所去掉的数字的位置和组成的新的正整数(N不超过100位)。 • 数据结构设计:和上一节对高精度正整数的处理一样,将输入的高精度数存储为字符串格式。根据输出要求设置数组,在删除数字时记录其位置。

  22. 2 可绝对贪婪问题-例4.3-问题分析 • 通过“枚举归纳”设计算法,实例(s=3) : • n1=“1 2 4 3 5 8 6 3” • 贪婪策略 • 在位数固定的前提下,让高位的数字尽量小其值就较小; • 删除高位较大的数字; • 具体地相邻两位比较若高位比低位大则删除高位。 • n1=“1 2 4 3 5 8 6 3” • 4比3大 删除 “1 2 3 5 8 6 3” • 8比6大 删除 “1 2 3 5 6 3” • 6比3大 删除 “1 2 3 5 3”

  23. 2 可绝对贪婪问题-例4.3-问题分析 • 再一个实例: • n2=“2 3 1 1 8 3” • 3比1大 删除 “2 1 1 8 3” • 2比1大 删除 “ 1 1 8 3” • 8比3大 删除 “ 1 1 3” • 由实例1,相邻数字只需要从前向后比较;而从实例2中可以看出当第i位与第i+1位比较,若删除第i位后,必须向前考虑第i-1位与第i+1位进行比较,才能保证结果的正确性。

  24. 2 可绝对贪婪问题-例4.3-问题分析 • 由这个实例看出,经过对n3相邻比较一个数字都没有删除,这就要考虑将后三位进行删除; • n3=”1 2 3 4 5 6 7” s=3 • 当然还有可能,在相邻比较的过程中删除的位数小于s时,也要进行相似的操作。 • n4=”1 2 0 0 8 3” s=3 • 2比0大 删除 “1 0 0 8 3” • 1比0大 删除 “ 0 0 8 3” • 8比3大 删除 “ 0 0 3” • 由这个实例子又能看出,当删除掉一些数字后,结果的高位有可能出现数字“0”,直接输出这个数据不合理,要将结果中高位的数字“0” 删除掉,再输出。特别地还要考虑若结果串是“0000”时,不能将全部“0”都删除,而要保留一个“0”最后输出。

  25. 2 可绝对贪婪问题-例4.3-算法设计 • 算法设计: • 根据以上实例分析,算法主要由四部分组成:初始化、相邻数字比较(必要时删除)、处理比较过程中删除不够s位的情况和结果输出。 • 其中删除字符的实现方法很多,如: • 1)物理进行字符删除,就是用后面的字符覆盖已删除的字符,字符串长度改变。这样可能会有比较多字符移动操作,算法效率不高。 • 2) 可以利用数组记录字符的存在状态,元素值为“1”表示对应数字存在,元素值为“0”表示对应数字已删除。这样避免了字符的移动,字符串长度不会改变,可以省略专门记录删除数字的位置。但这样做前后数字的比较过程和最后的输出过程相对复杂一些。

  26. 2 可绝对贪婪问题-例4.3-算法设计 • 3)同样还是利用数组,记录未删除字符的下标,粗略的过程如下: • n=“1 2 4 3 5 8 3 3” s=3 1 2 3 4 5 6 7 8 • 4比3大 删除 “1 2 4 3 5 8 3 3” 1 2 4 5 6 7 8 • 8比3大 删除 “1 2 4 3 5 8 3 3” 1 2 4 5 7 8 • 5比3大 删除 “1 2 4 3 5 8 3 3” 1 2 4 7 8 • 这时数组好象是数据库中的索引文件。此方式同样存在操作比较复杂的问题。

  27. 算法设计1: 一种简单的控制相邻数字比较的方法是每次从头开始,最多删除s次,也就从头比较s次。按题目要求设置数组data记录删除的数字所在位置。 delete(char n[],int b,int k) { int i; for(i=b;i<= length(n)-k;i=i+1) n[i]=n[i+k]; }

  28. main() {char n[100]; int s,i,j,j1,c,data[100],len; input(n); input(s); len=length(n); if(s>len) {print(“data error”); return;} j1=0; for (i=0;i<=s ;i=i+1) {for (j=1;j<=length(n);j=j+1) if (n[j]>n[j+1]) //贪婪选择 { delete(n,j,1); if (j>j1) data[i]=j+i; //记录删除数字位置 else data[i]=data[i-1]-1; //实例2向前删除的情况 j1=j; break; } if( j>length(n)) break;} for (i=i;i<=s;i=i+1) { j=len-i+1;delete(n,j,1); data[i]=j;} while (n[1]='0' and length(n) >1) delete(n,1,1); //将字符串首的若干个“0”去掉 print(n); for (i=1;i<=s;i=i+1) print(data[i],' '); } i控制删除字符的个数 j控制相邻比较操作的下标

  29. 算法设计2: 删除字符的方式同算法1,只是删除字符后不再从头开始比较,而是向前退一位进行比较,这样设计的算法2的效率较算法1要高一些。delete( )函数同前。 变量i控制删除字符的个数,变量j控制相邻比较操作的下标,当删除了第j个字符后,j赋值为j-1,以保证实例2(字符串n2)出现的情况得到正确处理。

  30. main(){ char n[100]; int s,i,j,j1,data[100],len; input(n); input(s); len=length(n); if(s>len){ print(“data error”); return; } i=0; j=1; j1=0; while(i<s and j<=length(n)-1){ while(n[j]<=n[j+1]) j=j+1; if (j<length(n)){ delete(n,j,1); if (j>j1) data[i]=j+i; else data[i]=data[i-1]-1; i=i+1; j1=j; j=j-1; } } delete(char n,int b,int k){ int i; for(i=b;i<= length(n)-k;i=i+1) n[i]=n[i+k]; } for (i=i;i<=s;i=i+1){ j=len-i+1; delete(n,j,1); data[i]=j; } while (n[1]='0' and length(n) >1) delete(n,1,1); print(n); for (i=1;i<=s;i=i+1) print(data[i],' '); }

  31. 2 可绝对贪婪问题-例4.4 数列极差问题 例4.4 在黑板上写N个正整数排成一个数列,进行如下操作:每一次擦去其中的两个数a和b,然后在数列中加入一个数a×b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得到的数中,最大的记作max,最小的记作min,则该数列的极差定义为M=max-min。

  32. 2 可绝对贪婪问题-例4.4-问题分析 通过实例来认识题目中描述的计算过程。 对三个具体数据3,5,7讨论,可能有以下三种结果: (3*5+1)*7+1=113,(3*7+1)*5+1=111, (5*7+1)*3+1=109 结论:先运算小数据得到的是最大值,先运算大数据得到的是最小值。

  33. 下面以三个数为例证明此题用贪心策略求解的合理性,不妨假设:a<b=a+k1<c=a+k1+k2,k1,k2>0,则有以下几种组合计算结果:下面以三个数为例证明此题用贪心策略求解的合理性,不妨假设:a<b=a+k1<c=a+k1+k2,k1,k2>0,则有以下几种组合计算结果: 1)(a*b+1)*c+1=a*a*a+(2k1+k2)a*a+(k1(k1+k2)+1)*a+k1+k2+1 2)(a*c+1)*b+1=a*a*a+(2k1+k2)a*a+(k1(k1+k2)+1)*a+k1+1 3)(b*c+1)*a+1=a*a*a+(2k1+k2)a*a+(k1(k1+k2)+1)*a+1 显然此问题适合用贪婪策略,不过在求最大值时,要先选择较小的数操作。求最小值时,要先选择较大的数操作。这是一道两次运用贪心策略解决的问题。

  34. 2 可绝对贪婪问题-例4.4-算法设计 1)不断从现有的数据中,选取最大和最小的两个数,计算后的结果继续参与运算,直到剩余一个数算法结束。 2) 选取最大和最小的两个数较高效的算法是用二分法完成, 这里仅用简单的逐个比较方法来求解。注意到由于找到的两个数将不再参与其后的运算,其中一个用它们的计算结果代替,另一个用当前的最后一个数据覆盖即可。所以不但要选取最大和最小,还必须记录它们的位置,以便将其覆盖。 3)求max、min过程必须独立,即求max和min都必须从原始数据开始,否则不能找到真正的max和min。

  35. 1)由设计2)、3)知,必须用两个数组同时存储初始数据。1)由设计2)、3)知,必须用两个数组同时存储初始数据。 2)求最大和最小的两个数的函数至少要返回两个数据,方便起见用全局变量实现。 int s1,s2; main() {int j,n,a[100],b[100],max,min; print(“How mang data?”); input(n); print(“input these data”); for (j=1;j<=n;j=j+1) {input(a[j]); b[j]=a[j];} min= calculatemin(a,n); max= calculatemax(b,n); print(“max-min=”, max-min) }

  36. calculatemin(int a[],int n) { int j; while (n>2) { max2(a,n); a[s1]= a[s1]* a[s2]+1; a[s2]=a[n]; n=n-1;} return(a[1]* a[2]+1); } max2(int a[],int n) { int j; if(a[1]>=a[2]) { s1=1; s2=2;} else { s1=2; s2=1;} for (j=3;j<=n;j++) { if (a[j]>a[s1]) { s2=s1; s1=j;} else if (a[j]>a[s2]) s2=j; } }

  37. calculatemax(int a[],int n) { int j; while (n>2) { min2(a,n); a[s1]= a[s1]* a[s2]+1; a[s2]=a[n]; n=n-1;} return(a[1]* a[2]+1); } min2(int a[ ],int n) { int j; if(a[1]<=a[2]) { s1=1; s2=2;} else { s1=2; s2=1;} for (j=3;j<=n;j++) if (a[j]<a[s1]) { s2=s1; s1=j;} else if (a[j]<a[s2]) s2=j; }

  38. 2 可绝对贪婪问题-例4.4-算法分析 算法的主要操作就是比较查找和计算,都是线性的,因此算法的时间复杂度为O(n)。由于计算最大结果和计算最小结果需要独立进行,所以算法的空间复杂度为O(2n)。

  39. 2 可绝对贪婪问题-例4.5-问题分析 例4.5 设计一个算法, 把一个真分数表示为埃及分数之和的形式。所谓埃及分数,是指分子为1的分数。如:7/8=1/2+1/3+1/24。 基本思想:逐步选择分数所包含的最大埃及分数,这些埃及分数之和就是问题的一个解。 如:7/8>1/2, 7/8-1/2>1/3, 7/8-1/2-1/3=1/24。 过程如下: 1)找最小的n(最大的埃及分数1/n),使分数f>1/n; 2)输出1/n; 3)计算f=f-1/n; 4)若此时的f是埃及分数,输出f,算法结束,否则返回1)。

  40. 2 可绝对贪婪问题-例4.5-问题模型 • 记真分数F=A/B;对B/A进行整除运算,商为D,余数为0<K<A,它们导出关系如下: • B=A*D+K,B/A=D+K/A<D+1,A/B>1/(D+1),记C=D+1。 • 这样分数F所包含的“最大”埃及分数就是1/C。 进一步计算:A/B-1/C=(A*C-B)/B*C • 也就是说继续要解决的是有关分子为A=A*C-B,分母为B=B*C的问题。

  41. 2 可绝对贪婪问题-例4.5-算法设计 由以上数学模型,算法过程如下: 1)设某个真分数的分子为A(≠1),分母为B; 2)把B除以A的商的整数部分加1后的值作为埃及 分数的一个分母C; 3)输出1/C; 4)将A乘以C减去B作为新的A; 5)将B乘以C作为新的B; 6)如果A大于1且能整除B,则最后一个分母为B/A; 7)如果A=1,则最后一个分母为B;否则转步骤2)。

  42. 实例:7/8=1/2+1/3+1/24的解题步骤: 同样用变量A表示分子,变量B表示分母; C=8/7+1=2 //说明7/8>1/2, 打印1/2 A=7*2-8=6,B=B*C=16 //计算7/8-1/2=(7*2-8)/(7*2)=6/16=A/B C=16/6+1=3 //说明16/6>1/3, 打印1/3 A=6*3-16=2,B=B*C=16*3=48 //计算6/16-1/3=(6*3-16)/(16*3)=2/48=A/B A>1但B/A为整数24,打印1/24 结束。

  43. 2 可绝对贪婪问题-例4.5-算法 main( ) { int a,b,c; print(“input element”); input(a); print(“input denominator”); input(b); if(a>=b) print(“input error”); else if (a=1 or b mod a=0) print( a, "/",b, "=" 1, "/",b/a); else   while(a<>1) { c = b /a + 1    a = a * c – b; b = b * c;    print( "1/",c);    if( a > 1) print("+"); if (b mod a =0 ) { print ("1/"; b / a); a=1; } }    }

  44. 3 相对贪婪问题-例4.6-取数游戏 有2个人轮流取2n个数中的n个数,取数之和大者为胜。请编写算法,让先取数者胜,模拟取数过程。

  45. 3 相对贪婪问题-例4.6-问题分析 这个游戏一般假设取数者只能看到2n个数中两边的数,用贪婪算法的情况: 若一组数据为:6,16,27,6,12,9,2,11,6,5。用贪婪策略每次两人都取两边的数中较大的一个数,先取者胜。 以A先取为例,取数结果: A 6,27,12,5,11=61 胜 B 16,6,9,6,2=39

  46. 3 相对贪婪问题-例4.6-问题分析 若选另一组数据:16,27,7,12,9,2,11,6。仍用贪婪算法,先取者A败。 取数结果: A 16,7,9,11=43 B 27,12,6,2=47胜 若只能看到两边的数据,则此题无论先取还是后取都无必胜的策略。这时一般的策略是用近似贪婪算法。 但若取数者能看到全部2n个数,则此问题可有一些简单的方法,有的虽不能保证所取数的和是最大,却是一个先取者必胜的策略。

  47. 3 相对贪婪问题-例4.6-数学模型 数学模型:N个数排成一行,从左到右编号,依次为1,2,…,N,因为N为偶数,又因为我们先取数,计算机后取数,所以一开始我们既可取到一个奇编号数,又可取到一个偶编号数。 若我们第一次取奇编号数,则计算机只能取到偶编号数; 若我们第一次取偶编号数,则计算机只能取到奇编号数; 所以,只要比较奇编号数之和与偶编号数之和谁大,以决定最开始我们是取奇编号数还是偶编号数即可。(若同样大,我们第一次可任意取数,因为当两和相同时,先取者胜。)

  48. 3 相对贪婪问题-例4.6-算法设计 算法设计:只需分别计算一组数的奇数位和偶数位的数据之和,然后先取数者可以确定必胜的取数方式。 以下面一排数为例:1 2 3 10 5 6 7 8 9 4 奇编号数之和为25(=1+3+5+7+9),小于偶编号数之和为30(=2+10+6+8+4)。我们第一次取4,以后,计算机取哪边数我们就取哪边数(如果计算机取1,我们就取2;如果计算机取9,我们就取8)。这样可保证我们自始自终取到偶编号数,而计算机自始自终取到奇编号数。

  49. main( ) { int i,s1,s2,data; input(n); s1=0; s2=0; for(i=1;i<=n;i=i+1) { input( data); if (i mod 2=0) s2=s2+data; elses1=s1+data; if(s1>s2) print(“first take left”); else print(“first take right”); 结论:解决问题时数学模型的选择是非常重要的。

  50. 3 相对贪婪问题-例4.7-多机调度问题 • 设有n个独立的作业{1,2,…, n },由m台相同的机器进行加工处理。 • 作业i所需的处理时间为ti 。现约定,每个作业均可在任何一台机器上加工处理,但未完工前不允许中断处理。作业不能拆分成更小的子作业。 • 多机调度问题要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。

More Related