NOIP基础算法——贪心和分治(1).ppt
《NOIP基础算法——贪心和分治(1).ppt》由会员分享,可在线阅读,更多相关《NOIP基础算法——贪心和分治(1).ppt(115页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、一、分治思想一、分治思想n 分治法,又叫分治策略,顾名思义,。n 它的基本思想:对于难以直接解决的规模较大的问题,把它分解成若干个能直接解决的相互独立的子问题,递归求出各子问题的解,再合并子问题的解,得到原问题的解。n 通过减少问题的规模,逐步求解,能够明显降低解决问题的复杂度。二、分治法的适用条件二、分治法的适用条件n 能使用分治法解决的问题,它们一般具备以下几个特征: 该问题可分解成若干相互独立、规模较小的相同子问题; 子问题缩小到一定的程度就能轻易得到解; 子问题的解合并后,能得到原问题的解;n 分治法在信息学竞赛中应用非常广泛,使用分治策略能生成一些常用的算法和数据结构,如快排、最优二
2、叉树、线段树等;还可以直接使用分治策略,解决一些规模很大、无法直接下手的问题。三、分治的三步骤三、分治的三步骤n分解:分解:将要解决的问题分解成若干个规模较小的同类子问题;n解决:解决:当子问题划分得足够小时,求解出子问题的解。n合并:合并:将子问题的解逐层合并成原问题的解。分治算法设计过程图分治算法设计过程图n 在划分问题时,可以采用递归策略,把一个大问题逐步分解成规模较小的子问题,直至可以直接求出子问题的解;再将子问题逐层合并,返回到顶层,得到原问题的解。n 根据分治策略的划分原则,把原问题划分成多少个子问题才合适呢?各个子问题的规模应该多大才合适呢?n 一般来说,每次划分成2个子问题,每
3、个子问题的规模差不多最合适。合并解时要因题而异,有些问题递归分解完能直接得到原问题的解,有些问题需逐层合并,得到原问题的解。四、分治的框架结构四、分治的框架结构procedure Divide()begin if(问题不可分问题不可分)then/解决解决 begin 直接求解;直接求解; 返回问题的解;返回问题的解; end else begin 对原问题进行分治;对原问题进行分治;/分解分解 递归对每一个分治的部分进行求解递归对每一个分治的部分进行求解; /解决解决 归并整个问题,得出全问题的解归并整个问题,得出全问题的解; /合并合并 endend;n 例题例题1 1:给:给n n个数,求
4、它们之中最大值和最小值,要求比个数,求它们之中最大值和最小值,要求比较次数尽量小。较次数尽量小。分析:分析:假设数据个数为n,存放在数组a1.n中。可以直接进行比较: minn:=a1;maxx:=a1; for i:=2 to n do if aimaxx then maxx:=ai; else if aixr1 then begin maxx:=xr2;minn:=xr1;end else begin maxx:=xr1;minn:=xr2;end end else begin d:=(r1+r2)/2; pd(r1,d,max1,min1); pd(d+1,r2,max2,min2);
5、if max1max2 then maxx:=max1;else maxx:=max2; if min1=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后4位。【文件输入文件输入】输入仅一行,有四个数,依次为a、b、c、d【文件输出文件输出】输出也只有一行,即三个根(从小到大输出)【样例输入样例输入】1 -5 -4 20【样例输入样例输入】-2.00 2.00 5.00n 如果精确到小数点后两位,可用简单枚举法:将x从-100.00 到100.00(步长0.01)逐一枚举,得到20000个 f(x),取其值与0最接近的三个f(x),对应的x即为答案。而题目已改
6、成精度为小数点后4位,枚举算法时间复杂度将达不到要求。n 直接使用求根公式,极为复杂。加上本题的提示给我们以启迪:采用二分法逐渐缩小根的范围,从而得到根的某精度的数值。n A.A.当已知区间当已知区间(a,b)(a,b)内有一个根时;内有一个根时;n 用二分法求根,若区间(a,b)内有根,则必有f(a)*f(b)b或f(a+b)/2)=0,则可确定根为(a+b)/2并退出过程; 、若f(a)*f(a+b)/2)0,则必然有f(a+b)/2)*f(b)=1。因此可知:在-100,-99、-99,-98、99,100、100,100这201个区间内,每个区间内至多只能有一个根。即:除区间100,1
7、00外,其余区间a,a+1,只有当f(a)=0或f(a)*f(a+1)0时,方程在此区间内才有解。若f(a)=0 ,解即为a;若f(a)*f(a+1)0 ,则可以利用A中所述的二分法迅速出找出解。如此可求出方程的所有的解。procedure Divide(x1,x2:double)Begin var x0,y0,y1,y2:double; x0:=(x1+x2)div 2; y1:=cal(x1);y2:=cal(x2);y0:=cal(x0); if(x2-x10.00001 and y1*y20)then begin write(x2+x1)div 2:0:4);exit;end if(y
8、1*y01)then divide(x1,x0); if(y0*y21)then divide(x0,x2);End;n 归并排序的基本思想:归并排序的基本思想:归并排序充分应用分治算法的策略,通过二分的思想,将n个数最终分成n个单独的有序数列,每个数列中仅有一个数字;再将相邻的两列数据合并成一个有序数列;再重复上面的合并操作,直到合成一个有序数列。按照分治三步法来说: (1 1)划分:)划分:把序列分成元素个数相等的两半; (2 2)递归求解:)递归求解:把两半分别排序; (3 3)合并:)合并:把两个有序表合成一个有序表;分析分析n 显然,前两部分是很容易完成的,关键在于如何把两个有关键在
9、于如何把两个有序表合成一个序表合成一个。每次只需要把两个有序表中当前的最小元素加以比较,删除较小元素并加入合并后的新表中。procedure MergeSort(left,right:integer)/归并排序归并排序begin if left=right then exit; /只有一个元素只有一个元素 mid:=(left+right)div 2; /找中间位找中间位 MergeSort(left,mid); /对左边归并对左边归并 MergeSort(mid+1,right); /对右边归并对右边归并 i:=left;j:=mid+1,p:=left; /合并左右合并左右 while(i
10、=mid and jaj)then begin tempp:=aj;inc(p);inc(j);end else begin tempp:=ai;inc(p);inc(i);end while(i=mid)do begin tempp:=ai;inc(p);inc(i);end while(j=right)do begin tempp:=aj;inc(p);inc(i);end for i:=left to right do ai:=tempi; End;【变形变形1 1】求逆序对数目求逆序对数目例题例题3 3:求:求“逆序对逆序对”n 给定一整数数组A=(A1,A2,An), 若iAj,则就
11、为一个逆序对。例如数组(3,1,4,5,2)的逆序对有,。问题是,输入n和A数组,统计逆序对数目。n 数据范围:1=naj then c:=c+1;n 时间效率不尽如人意时间效率不尽如人意.n 问题出现在哪里呢?问题出现在哪里呢?求逆序对的方法:求逆序对的方法:n 求逆序对有多种方法, 目前使用比较广泛且实现比较简单的主要有三种算法: 1、归并排序 2、线段树 3、树状数组n采用二分法求解采用二分法求解:n记数列记数列ast,ed的逆序对数目为的逆序对数目为d(st,ed);n mid=(st+ed)/2,则有:则有: d(st,ed)=d(st,mid)+d(mid+1,ed)+F(st,m
12、id,ed)n其中其中F(st,mid,ed)表示一个数取自表示一个数取自ast,mid,另一个另一个数取自数取自amid+1,ed所构成的逆序对数目。所构成的逆序对数目。n 和归并排序一样,划分和递归求解都好办,关键在于合并:如何求出i在左边,而j在右边的逆序对数目呢?统计的常见技巧是“分类”。我们按照j的不同把这些“跨越两边”的逆序对进行分类:只要对于右边的每个j,统计左边比它大的元素个数f(j),则所有f(j)之和便是答案。n 幸运的是,归并排序可以帮助我们“顺便”完成f(j)的计算:由于合并操作是从小到大进行排序的,当右边的aj复制到T中时,左边还没有来得及复制到T的那些数就是左边所有
13、比aj大的数。此时累加器中加上左边元素个数mid-i+1即可。n 即把即把“if(aiaj)then begin tempp:=aj;inc(p);inc(j);endif(aiaj)then begin tempp:=aj;inc(p);inc(j);end n 改为改为“if(aiaj)then if(aiaj)then begin begin tot:=tot+mid-i+1;tot:=tot+mid-i+1;tempp:=aj;inc(p);inc(j);endtempp:=aj;inc(p);inc(j);end 【问题问题】给出从小到大排列的n个不同数a1an,试判断元素x是否出现
14、在表中。n 方法方法1 1:顺序查找。:顺序查找。即一个一个进行寻找,时间复杂度为O(n)。这个方法并没有用到“n个数从小到大排列”这一个关键条件,因而时间效率低下。n 只需要比较log2n个元素。假设需要在aLar中查找元素x。n 划分:划分:检查某个元素am(L=mx,那么元素只可能在aLam-1中 如果amr exit(-1); m:=(L+r)div 2; if am=x bsh:=m; else if amx then bsh:=bsh(L,m-1,x); else bsh:= bsh(m+1,r,x);End;function bsh(L,r,x:integer):integer;
15、 Begin var m:integer; while(Lx then r:=m-1 else L:=m+1; end bsh:=-1; /查找不成功查找不成功End; function Erfen(L,r,x:integer):integer; begin var mid:integer; while(Lr)do begin mid:=(L+r)div 2; if x=amid then r:=mid else L:=mid+1; end; Erfen:= L; end;【扩展扩展2】二分查找求上界,即最后一次出现位置的后一个二分查找求上界,即最后一次出现位置的后一个位置位置【变形变形1 1
16、】:奇怪的函数:奇怪的函数 【问题描述问题描述】使得xx达到或超过n位数字的最小正整数x是多少? 【文件输入文件输入】输入一个正整数n。 【文件输出文件输出】输出使得xx达到n位数字的最小正整数x。【变形变形2 2】:统计:统计 【问题描述问题描述】给你一个有n(n=100000)个整数的序列,接下来有m(m=10000)个询问,每个询问为一个整数,需要你输出在给出的序列中,此整数有多少个?【变形变形3 3】:查找等值点:查找等值点 【问题描述问题描述】n个不同整数从小到大排序后放在数组A1An中,是否存在i,使得Ai=i?若存在,试找到此点。 【问题问题】计算计算a an n mod kmo
17、d k的值的值 ,其中,其中n=10n=109 9。方法方法1:朴素算法。每次乘以:朴素算法。每次乘以a,时间复杂度时间复杂度O(n)。 function power(a,n:integer):integer; begin var x:integer; x:=1; for i:=1 to n do x:=x*a; power:=x; end;很明显,此程序要超时。很明显,此程序要超时。n划分:如果划分:如果n是偶数,则考虑是偶数,则考虑x=n div 2 否则考虑否则考虑x=(n-1) div 2n递归求解:计算递归求解:计算ax。n合并:如果合并:如果n是偶数,则是偶数,则an=(ax)2,
18、否则,否则an=(ax)2*a根据这个方法很容易写出程序:根据这个方法很容易写出程序:function power(a,n:integer):integer;Begin if n=0 begin power:=1;exit;end else if n mod 2=1 then /n为奇数的情况为奇数的情况 begin x:=power(a,(n-1)div 2); power:=(x*x)mod k*a)mod k; end else begin /n为偶数的情况为偶数的情况 x:=power(a,n div 2); power:=x*x mod k; end;End; read(a,b,k)
19、;/输入三个数输入三个数 t:=b; while t0 do begin inc(len);clen:=t mod 2;t:=t div 2;end;/转为二进制转为二进制 s:=1; for i:=len downto 1 do /用二分法实现用二分法实现ab mod k begin s:=s*s mod k; if ci=1 then s:=(a mod k)*s)mod k;/是奇数是奇数 end; writeln(s);/输出输出ab mod k【例题例题】Fibonacci数数【题目描述题目描述】Fibonacci数列定义为:fi=fi-2+fi-1 (i2),其中f1=1,f2=1
20、。现在请你求Fibonacci数列的第n项。【文件输入文件输入】输入文件只有一行为一个整数n(1=n=231-1)。【文件输出文件输出】输出文件只有一行为一个整数,表示Fibonacci数列的第n项mod 32768的值。【样例输入样例输入】4【样例输出样例输出】3【数据范围数据范围】 对于20%的数据,1=n=1000 对于40%的数据,1=n=10000000 对于100%的数据,1=n=231-1 n朴素算法O(n),肯定超时procedure Fib(n:integer)begin var i:integer; f0:=0;f1:=1; for i:=2 to n do fi:=fi-
21、1+fi-2;end;n 可用倍增法在可用倍增法在O(logn)时间内求出幂时间内求出幂(忽略高精度忽略高精度)2212231212111110.11101110nnnnnnnnnnXFFXFFXFFFFFFFn若fi=fi-1+fi-2+fi-3,如何计算求出fn?【例题例题】比赛安排比赛安排【问题描述问题描述】设有2n(n=6)个球队进行单循环比赛,计划在2n -1天内完成,每个队每天进行一场比赛。设计一个比赛的安排,使在2n -1天内每个队都与不同的对手比赛。例如n=2时的比赛安排为: 队 1 2 3 4 比赛 1-2 3-4 第一天 1-3 2-4 第二天 1-4 2-3 第三天 【文
22、件输入文件输入】一个整数n。【文件输出文件输出】输出比赛安排表。【样例输入样例输入】2【样例输出样例输出】 1-2 3-4 1-3 2-4 1-4 2-3 分析分析1 1:递归形式实现:递归形式实现n 由于由于N个运动员要进行单循环比赛,且在个运动员要进行单循环比赛,且在N-1天内要结束全天内要结束全部比赛,经过分析,当且仅当部比赛,经过分析,当且仅当N为为2的整次幂时,问题才有的整次幂时,问题才有解,当然解是不唯一的。这样可以将运动员分成两组:解,当然解是不唯一的。这样可以将运动员分成两组: 1,2,N/2 和和 N/2+1,N/2+2,N。给第一组运动员安排一。给第一组运动员安排一个比赛日
23、程,得到一个个比赛日程,得到一个N/2阶的方阵阶的方阵A1;同时给第二组的;同时给第二组的运动员安排一个比赛日程,同样会得到一个运动员安排一个比赛日程,同样会得到一个N/2阶的一个方阶的一个方阵阵A2。考虑到比赛的性质,设定第。考虑到比赛的性质,设定第I个运动员在某一天的个运动员在某一天的比赛对手为第比赛对手为第K个运动员,则第个运动员,则第K个运动员在同一天的比赛个运动员在同一天的比赛对手必然是第对手必然是第I个运动员,即若有个运动员,即若有AI,J=K,则,则AK,J=I。因此原问题的解因此原问题的解(一个一个N阶方阵阶方阵)可以由分解后的两个子问题可以由分解后的两个子问题的解,合并起来。
24、同时每一个子问题又可以按照上述的二的解,合并起来。同时每一个子问题又可以按照上述的二分法分解下去,直至每个组中仅有分法分解下去,直至每个组中仅有2个运动员时为止。个运动员时为止。 procedure arrangment(K,N:integer);从K号运动员起的共N员运动员单循环比赛日程表的过程 begin if n=2 then 处理只有2名运动员的情况,递归终止条件 begin AK,0:=K;AK,1:=K+1; AK+1,0:=K+1; AK+1,1:=K; end else begin arrangment(K,N div 2); arrangment(K+N div 2,N di
25、v 2); 递归分解原问题与求解子问题 for i:=K to K+(N div 2) 1 do 合并子问题的解,构造原问题的解Ai,j for j:=(N div 2) to N-1 do Ai,j:=Ai+(N div 2),j-(N div 2); for i:=K+(N div 2) to K+N 1 do for j:=(N div 2) to N-1 do Ai,j:=Ai-(N div 2),j-(N div 2); end;end;方法方法1 1:递归形式实现:递归形式实现n 初看此题,感觉无法下手,因为没有任何直接可用的算法和数据结构。n 仔细分析,可以发现,将问题进行分解,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NOIP 基础 算法 贪心 分治
限制150内