当前位置:文档之家› 第7章 分治算法

第7章 分治算法


//将当前序列在中间位置的数定义为中间数
//在左半部分寻找比中间数大的数 //在右半部分寻找比中间数小的数 //若找到一组与排序目标不一致的数对则交换它们
//继续找
//若未到两个数的边界,则递归搜索左右区间
【例2】用递归算法实现二分查找即:有20个已经从小到大排序好的数据,输入 一个数X,用二分查找算法,判断它是否在这20个数中。
3、方程f(x)的根 【问题描述】 求方程f(x)=2x+3x-4x=0在[1,2]内的根。 提示:2x可以表示成exp(x*ln(2))的形式。 【输入格式】 输入:[1,2]的区间值。 【输出格式】 输出:方程f(x)=0的根,x的值精确小数点10位。 【输入样例】 1 2 【输出样例】 1.5071105957 4、求一元三次方程的解 【问题描述】 有形如: ax3+bx2+cx+d=0一元三次方程。给出该方程中各项的系数 (a, b, c, d 均为实数 ),并约定该方程存在三个不同实根 (根的范围在 -100 至 100之间 ),且根与根之差的绝对值 >=1。要求由小到大依次在同一行上 输出这三个实根。 【输入格式】 输入:a,b,c,d 【输出格式】 输出: 三个实根(根与根之间留有空格) 【输入样例】Equ.in 1 –5 –4 20 【输出样例】Equ.out -2.00 2.00 5.00
【上机练习】
1、用非递归方法编写【例2】 2、求N个数A1,A2,A3……AN中的最大值MAX和最小值MIN。 【算法分析】 策略一:把n(n>2)个数据先分成两组,分别求最大值、最小值,然后 分别将两组的最大值和最小值进行比较,求出全部元素的最大值和最小 值。若分组后元素还大于2,则再次分组,直至组内元素小于等于2。 策略二:如果N等于1时,MAX=MIN=A1,如果N=2时,MAX=A1, MIN=A2或MAX=A2,MIN=A1,这是非常简单的,所以此题可把所有的 数作为一个序列,每次从中取出开头两个数,求共MAX,MIN,然后再 从剩余的数中取开头两个数,求其MAX、MIN后与前一次的MAX、MIN 比较,可得出新的MAX、MIN,这样重复下去,直到把所有的数取完 (注意最后一次取可能是只有一个数),MAX,MIN也就得到了。这就 是典型的分治策略。注意:这样做与把所有数字排序后再取MAX、MIN 要快得多。
//递归过程
// 取中间位置点 //找到查找的数,输出结果 //找不到该数 //在后半中查找 //在前半中查找
// 输入排序好的数 // 输要查找的数 // 递归过程
【例3】一元三次方程求解 有形如:ax3+bx2+cx+d=0这样的一个一元三次方程。给出该方程中各项的 系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100至 100之间),且根与根之差的绝对值≥1。 要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精 确到小数点后2位。 提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)< 0,则在(x1,x2)之间一定有一个根。 输入:a,b,c,d 输出:三个实根(根与根之间留有空格) 【输入输出样例】 输入:1 -5 -4 20 输出:-2.00 2.00 5.00 【算法分析】 这是一道有趣的解方程题。为了便于求解,设方程f(x)=ax3+bx2+cx+d=0, 设x的值域(-100至100之间)中有x, 其左右两边相距0.0005的地方有x1和x2两 个数,即 x1=x-0.0005,x2=x+0.0005。x1和x2间的距离(0.001)满足精度要求 (精确到小数点后2位)。若出现如图1所示的两种情况之一,则确定x为f(x)=0的 根。
【参考程序】 program car1(input,output); const zero=1e-4; var s,a,b,c,c0,c1,t1,t2,t3,t4:real; BEGIN assign(input,’car.in’); reset(input); assign(output,’car.out’); rewrite(output); readln(s,a,b); c0:=0; c1:=s; repeat c:=(c0+c1)/2; 【深入思考】 t3:=c/b; 现在把上述问题稍改一下,已 t1:=t3+(s-c)/a; 知A、B两地相距S=100公里,在A t4:=(c-t3*a)/(a+b); 地有n人,现有一辆汽车,此汽车 t2:=t3+t4+(s-(t3+t4)*a)/b; 除司机外只能载1人,已知汽车的 if t1<t2 then c1:=c else c0:=c; 速度为V1=50公里/小时,人的速度 until abs(t1-t2)<zero; 为V2=5公里/小时。要求设计一种 writeln(t1); 方案,使得最后一个人用最少的时 close(input);close(output) 间到达B。 END.
由此得出算法: 输入方程中各项的系数a,b,c,d ; for x←-100 to 100 do //枚举每一个可能的根 begin x1←x;x2←x+1; //确定根的可能区间 if f(x1)=0 then write(x1:0:2,’ ’) //若x1为根,则输出 else if (f(x1)*f(x2)<0) then //若根在区间[x1,x2]中 begin while x2-x1>=0.001 do //若区间[x1,x2]不满足精度要求,则循环 begin xx←(x2+x1)/2; //计算区间[x1,x2]的中间位置 if f(x1)*f(xx)<=0 then x2←xx //若根在左区间,则调整右指针 else x1←xx; //若根在右区间,则调整左指针 end;//while write(x1:0:2,’ ’); //区间[x1,x2]满足精度要求,确定x1 为根 end; //then end; //for 其中f(x)的函数说明如枚举法所示。
【例1】快速排序(递归算法)
procedure qsort(l,r:integer); var i,j,mid,p:integer; begin i:=l; j:=r; mid:=a[(l+r) div 2]; repeat while a[i]<mid do inc(i); while a[j]>mid do dec(j); if i<=j then begin p:=a[i]; a[i]:=a[j]; a[j]:=p; inc(i); dec(j); end; until i>j; if l<j then qsort(l,j); if i<r then qsort(i,r); end;//sort
【算法分析】 最佳方案为:甲先乘车到达K处后下车步行,小车再回头接已走到C处的乙, 在D处相遇后,乙再乘车赶往B,最后甲、乙一起到达B地。如下图所示,这时所 用的时间最短。这样问题就转换成了求K处的位置,我们用二分法,不断尝试, 直到满足同时到达的时间精度。
算法框架如下: 1、输入s,a,b; 2、c0:=0;c1:=s;c:=(c0+c1)/2; 3、求t1,t2; 4、如果t1<t2,那么c:=(c0+c)/2 否则 c:=(c+c1)/2; 反复执行3和4,直到abs(t1-t2)满足精度要求(即小于误差标准)。
program ex11_2; var a:array[1..20]of integer; n,i,m,x,y:integer; procedure jc(x,y:integer); var k:integer; begin k:=(x+y)div 2; if a[k]=m then writeln('then num in',k:5); if x>y then writeln('no find') else begin if a[k]<m then jc(k+1,y); if a[k]>m then jc(x,k-1); end; end; begin readln(n); x:=1;y:=n; for i:=1to n do readln(a[i]); readln(m); jc(x,y); readln; end.
第七章 分治算法
所谓分治就是指的分而治之,即将较大规模的问题分解成几个较小规模 的问题,通过对较小规模问题的求解达到对整个问题的求解。当我们将问题分 解成两个较小问题求解时的分治方法称之为二分法。 分治的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这 些子问题互相独立且与原问题相同。找出各部分的解,然后把各部分的解组合 成整个问题的解。 1、解决算法实现的同时,需要估算算法实现所需时间。分治算法时间是 这样确定的: 解决子问题所需的工作总量(由子问题的个数、解决每个子问题的工作量 决定)合并所有子问题所需的工作量。 2、分治法是把任意大小问题尽可能地等分成两个子问题的递归算法。 3、分治的具体过程(以二分法为例): begin {开始} if ①问题不可分 then ②返回问题解 else begin ③从原问题中划出含一半运算对象的子问题1; ④递归调用分治法过程,求出解1; ⑤从原问题中划出含另一半运算对象的子问题2; ⑥递归调用分治法过程,求出解2; ⑦将解1、解2组合成整个问题的解; end; end; //结束
2.分治法 枚举根的值域中的每一个整数x(-100≤x≤100)。由于根与根之差的绝 对值≥1,因此设定搜索区间[x1,x2],其中x1=x,x2=x+1。若 ⑴f(x1)=0,则确定x1为f(x)的根; ⑵f(x1)*f(x2)>0,则确定根x不在区间[x1,x2]内,设定[x2,x2+1]为 下一个搜索区间 ⑶f(x1)*f(x2)<0,则确定根x在区间[x1,x2]内。 如果确定根x在区间[x1,x2]内的话(f(x1)*f(x2)<0),如何在该区间 找到根的确切位置。采用二分法,将区间[x1,x2]分成左右两个子区间: 左子区间[x1,x]和右子区间[x,x2](其中x=): 如果f(x1)*f(x)≤0,则确定根在左区间[x1,x]内,将x设为该区间的右 指针(x2=x),继续对左区间进行对分;如果f(x1)*f(x)>0,则确定根在 右区间[x,x2]内,将x设为该区间的左指针(x1=x),继续对右区间进 行对分; 上述对分过程一直进行到区间的间距满足精度要求为止(x2x1<0.001)。此时确定x1为f(x)的根。
相关主题