贪心与归纳算法

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

【改进】 在原算法基础上进行改进。下面给出新的算法: 1. 建立集合P={m..n} 2. 从n div 2到m每数构造一个集合c[i],包含该数在P中的所 有倍数(不包括i本身) 3. 从n div 2起找到第一个元素个数最少但又不为空的集合c[i] 4. 在d分值中加上i 5. 把i及c[i]集合从P集中删除,更新所有构造集合的元素 6. 检查所有构造集合,若还有非空集合,则继续3步骤,否 则打印、结束
与判断素数原理一样,对于一个数n,要求 其因子,只需求枚举到sqrt(n)即可,如果X是n 的因子,那么 n div x 也是n的因子。 求数n的所有因子的一种方法: for i:=1 to trunc(sqrt(n)) do if n mod i = 0 then begin writeln(i); writeln(n div i); end;
分析:
x
X
a0 最大公约数 a1
b0 最小公倍数 b1
则 x必须(1)整除a1;(2)是b1的因子 (3)gcd(x,a1)=a1 (4) x*b0/gcd(x,b0)=b1 枚举x,满足上述四个条件,统计个数。X比较显 然的范围为a1到b1. 问题: b1≤2,000,000,000,而x是b1的因子,问 题归约为如何比较快地求b1的所有因子?
算法伪代码:
• • • • • • • •
• • • •
设原数长度N,删除D位数 D := N - D;{留下数位数} Stack[0] := Chr(58);{字符9} Top := 1; For i := 1 to N do Begin 取出第i位数字C While (C > Stack[Top - 1]) And (Top + N - i > D) do Dec(Top);{如果当前位数字大于前面数字且已保留数位个数与剩 余数个数和大于需留下数位的个数,则删除前面的数字} Stack[Top] := C; Inc(Top) End; For i := 1 to D do Write(Stack[i])
样例输入: (1) 1 10 (2) 56 57 样例输出: (1) 5:12346789 4:123679 2:1379 3:17 1: (2) 0
【分析】 初看这一问题,很容易想到用贪心策略来求解,即选择 集合中最大的可以删除的数开始删起,直到不能再删除为止, 而且通过一些简单的例子来验证,这一贪心标准似乎也是正 确的,例如,当m=3,n=10时,集合P={3,…,10},运用上 述“贪心标准”可以得到这一问题的正确的最优解d=5+4+ 3=12,即其d-规则过程如下: 原集合:P={3,4,5,6,7,8,9,10} 1. a=5 P={3,4,6,7,8,9} d=5 2. a=4 P={3,6,7,9} d=5+4=9 3. a=3 p={7} d=5+4+3=12
问题1:集合删数简述
问题由两个子问题组成: (1) 构造一个多位数:1是集合元素;若P是集 合的元素,则2 * P +1,4*P+5也是集合的元素,取 出此集合中最小的K个元素,按从小到大的顺序组合 成一个多位数 (2)从多位数中删除M个数位上的数字,使得剩 下的数字最大
(1)分析集合元素特点:若P是集合的元素,则 2 * P +1,4*P+5也是集合的元素 ,即生成集合元 素的函数是单调递增的。 将2 * P +1与4*P+5产生的元素分成两个集合, 每次取两集合中最小的一个元素,显然只需比较 两集合中当前未被取走的第一个元素。 引入指针概念:设TOP1指向 2 * P +1当前未 被取走的第一个元素,TOP2指向4*P+5当前未被 取走的第一个元素。
题意简述: 给出a0,a1,b0,b1,求满足与a0的大公约为 a1,与b0的小公倍是b1的数的个数。 同时给出n组数据。 【数据范围】 对于 50%的数据,保证有 1≤a0,a1,b0, b1≤10000且 n≤100。 对于 100%的数据,保证有 1≤a0,a1,b0, b1≤2,000,000,000且 n≤2000。
但是,如果再仔细地分析一个例子,当m=3,n =18时,如果还是使用上述“贪心标准”,则得到 问题的d-规则总分为d=35,其d-规则序列为 (9,8,7,6,5),而实际上可以得到最大d-规则总分 为d=38,其对应的d-规则序列为(9,8,7,6,3,5)。 为什么会出现这样的反例呢?这是因为,问题 中要使得d-规则总分d值越大,不光是要求每一个d 分值越大越好,也要求取得的d分值越多越好。 因此,本题不能采用纯粹的贪心策略求解。
贪心算法
• 所谓贪心算法是指,在对问题求解时, 总是做出在当前看来是最好的选择。也就是 说,不从整体最优上加以考虑,他所做出源自文库 仅是在某种意义上的局部最优解。 • 贪心算法不是对所有问题都能得到整体 最优解,但对范围相当广泛的许多问题他能 产生整体最优解或者是整体最优解的近似解。
• 贪心算法的基本思路如下: • 1.建立数学模型来描述问题。 • 2.把求解的问题分成若干个子问题。 • 3.对每一子问题求解,得到子问题的局部 最优解。 • 4.把子问题的解局部最优解合成原来解问 题的一个解。 • 实现该算法的过程: • 从问题的某一初始解出发; • while 能朝给定总目标前进一步 do • 求出可行解的一个解元素; • 由所有解元素组合成问题的一个可行解;
关键词:队
比较TOP1,TOP2指向的元素,取最小的一 个,将取走元素队列的指针指向下一个元素。
例:生成5元素的集合数。 1 3 7 9 15 2 * P +1:3 7 15 19 4*P+5:9 17 33 41
a:=1; b:=1; p[1]:=1; For i:=2 to n do begin x:=p[a]*2+1; y:=p[b]*4+5; if x<=y then begin if x=y then inc(b); p[i]:=x; inc(a); end else begin p[i]:=y; inc(b); end; end;
2、d-规则问题。 对任意给定的m(m∈N+)和n(n∈N+),满足 m<n,构造一初始集合: P={x|m≤x≤n,x∈N+}(m,n≤100) 现定义一种d规则如下:若存在a∈P,且 存在K∈N+ ,K>1,使得Ka∈P,则修改P为: P=P-{y|y=ka,s∈N+ } ,并称该d规则具有分 值a。现要求编制一个程序,对输入的m,n值, 构造相应的初始集合P,对P每应用一次d规 则就累加其相应的分值,求能得到最大累加
辗转相除求最大公约数: 写法1: Function gcd(a, b : longint) : longint; begin if a mod b = 0 then exit(b); exit(gcd(b, a mod b)); end; 写法2: function gcd(m, n: longint): longint; var r: longint; begin while n <> 0 do begin r := m mod n; m := n; n := r; end; gcd := m; end;
复习: 1、模拟算法的核心思想:按问题描述的过 程编程解决问题,关键点为审题,理清解 决问题的步骤。
2、枚举算法分析步骤:(1)确定枚举对 象;(2)确定枚举范围;(3)剪枝提高 效率。
Noip2009 Hankson的趣味题
【问题描述】
Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家, 他的儿子名叫 Hankson。现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。 今天在课堂上,老师讲解了如何求两个正整数 c1和 c2 的 最大公约数和最小公倍数。现在 Hankson 认为自己已经熟 练地掌握了这些知识,他开始思考一个“求公约数”和 “求公倍数”之类问题的“逆问题” ,这个问题是这样的: 已知正整数 a0,a1,b0,b1,设某未知正整数 x 满足: 1. x 和 a0 的最大公约数是 a1; 2. x 和b0 的最小公倍数是 b1。 Hankson 的“逆问题”就是求出满足条件的正整数 x。但 稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存 在。因此他转而开始考虑如何求解满足条件的 x 的个数。 请你帮助他编程求解这个问题。
讨论: • 能否证明此贪心策略是正确的? • 能否找到其他更好的算法?
归纳策略
归纳法的基本思想
• 归纳法的基本思想是通过列举少量的特 殊情况,经过分析,最后找出一般的关系。 从本质上讲,归纳就是通过观察一些简单 而特殊的情况,最后总结出有用的结论或 解决问题的有效途径。
归纳法解题的过程
主体程序: for i := 1 to n do begin readln(a0, a1, b0, b1); {读入每组数} ans := 0; for j := a1 to trunc(sqrt(b1)) do{枚举可能值} if b1 mod j = 0 then begin{求满足条件(2)b1的因 子} k := b1 div j; if j mod a1 = 0 then ans := ans + Ord((gcd(j div a1, a0 div a1) = 1) and (b0 div gcd(j, b0) * j = b1)); {满足条件(1),同时满足条件(3)、(4)} if (j <> k) and (k mod a1 = 0) then ans := ans + Ord((gcd(k div a1, a0 div a1) = 1) and (b0 div gcd(k, b0) * k = b1)); end; writeln(ans); end;
问题A:
集合删数
问题描述: 一个集合有如下元素:1是集合元素;若P是集合的元素, 则2 * P +1,4*P+5也是集合的元素,取出此集合中最小的K个元 素,按从小到大的顺序组合成一个多位数,现要求从中删除M个 数位上的数字,使得剩下的数字最大,编程输出删除前和删除后 的多位数字。 注:不存在所有数被删除的情况` 输入格式: 输入的仅一行,K,M的值,K,M均小于等于30000。 输出格式: 输出为两行,第一行为删除前的数字,第二行为删除后的数 字。 样例输入: 5 4 样例输出: 137915 95
下面看m=3, n=18时的推演过程: 1. 初始P={3..18} 2. 找到i=9, c[i]={18}, P={3..8,10..17} 3. 找到i=8, c[i]={16}, P={3..7,10..15,17} 4. 找到i=7, c[i]={14}, P={3..6,10..13,15,17} 5. 找到i=6, c[i]={12}, P={3..5,10,11,13,15,17} 6. 找到i=3, c[i]={15}, P={4,5,10,11,13,17} 7. 找到i=5, c[i]={10}, P={4,11,13,17} 到此所有构造集合全部为空,d=9+8+7+6+3+5=38
(2)分析
1.高位越大越好; 2.因为数据很大,边取数字边处理,处理原 则是当前数留下,还是取代前面数留下。 如:13751967 留下2位数 1 3 751 96 97
3.当前数能否作为剩余序列的最高位?能, 则删除前面比自己小的数。 当前数是否取代前面留下的数的条件为: (1)当当前数大于前面数时; (2)总体保留位数(末删除数个数+末读入数 个数)大等于需留下的位数时; 删除前面保留的数
问题简述:
P为由m到n自然数组成的集合,如果P集 合中存在某元素a和该元素的倍数构成的元素 k*a,则从P中删去a和a倍数的元素,获得一个 a分值,称为运用一次d规则,不断运用d规则, 每运用一次d规则,累加一次a分值,求最大累 加分值的d规则序列。 输出每次使用d规则时的分值和集合p的变 化过程。
相关文档
最新文档