




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
4.1迭代算法4.1.1遞推法4.1.2倒推法4.1.3迭代法解方程4.1.1遞推法【例1】兔子繁殖問題問題描述:一對(duì)兔子從出生后第三個(gè)月開始,每月生一對(duì)小兔子。小兔子到第三個(gè)月又開始生下一代小兔子。假若兔子只生不死,一月份抱來一對(duì)剛出生的小兔子,問一年中每個(gè)月各有多少只兔子。問題分析:因一對(duì)兔子從出生后第三個(gè)月開始每月生一對(duì)小兔子,則每月新下小兔子的對(duì)兒數(shù)(用斜體數(shù)字表示)顯然由前兩個(gè)月的小兔子的對(duì)兒數(shù)決定。則繁殖過程如下:一月二月三月四月五月六月……111+1=22+1=33+2=55+3=8……算法1:
main(){inti,a=1,b=1;print(a,b);for(i=1;i<=10;i++){c=a+b;print(c);a=b;b=c;
}}數(shù)學(xué)建模:y1=y2=1,yn=yn-1+yn-2,n=3,4,5,……。算法2:
表4-1遞推迭代表達(dá)式123456789abc=a+ba=b+cb=a+cc=a+ba=b+cb=a+c……由此歸納出可以用“c=a+b;a=b+c;b=c+a;”做循環(huán)“不變式”。算法2如下:
main(){inti,a=1,b=1;
print(a,b);for(i=1;i<=4;i++){c=a+b;a=b+c;b=c+a;print(a,b,c);}}
算法2,最后輸出的并不是12項(xiàng),而是2+3*4共14項(xiàng)。
表4-2遞推迭代表達(dá)式123456789aba=a+bb=a+ba=a+bb=a+b……
由此歸納出可以用“a=a+b;b=a+b;”做循環(huán)“不變式”,從而得到以下算法3:main(){inti,a=1,b=1;print(a,b);for(i=1;i<=5;i++){a=a+b;b=a+b;print(a,b);}}算法3:【例2】求兩個(gè)整數(shù)的最大公約數(shù)。數(shù)學(xué)建模:輾轉(zhuǎn)相除法是根據(jù)遞推策略設(shè)計(jì)的。不妨設(shè)兩個(gè)整數(shù)a>b且a除以b商x余c;則a-bx=c,不難看出a、b的最大公約數(shù)也是c的約數(shù)(一個(gè)數(shù)能整除等式左邊就一定能整除等式的右邊),則a、b的最大公約數(shù)與b、c的最大公約數(shù)相同。同樣方法推出b、c的最大公約數(shù)與……,直到余數(shù)為0時(shí),除數(shù)即為所求的最大公約數(shù)。算法設(shè)計(jì):循環(huán)“不變式”第一次是求a、b相除的余數(shù)c,第二次還是求“a”“b”相除的余數(shù),經(jīng)a=b,b=c操作,就實(shí)現(xiàn)了第二次還是求“a”“b”相除的余數(shù),這就找到了循環(huán)不變式。循環(huán)在余數(shù)c為0時(shí)結(jié)束。
算法如下:main(){inta,b;input(a,b);if(b=0)
{print(“dataerror”);return;}else{c=amodb;whilec<>0{a=b;
b=c;
c=amodb;}}print(b);}4.1.2倒推法
所謂倒推法:是對(duì)某些特殊問題所采用的違反通常習(xí)慣的,從后向前推解問題的方法。如下面的例題,因不同方面的需求而采用了倒推策略。例1在不知前提條件的情況下,經(jīng)過從后向前遞推,從而求解問題。即由結(jié)果倒過來推解它的前提條件。又如例2由于存儲(chǔ)的要求,而必須從后向前進(jìn)行推算。另外,在對(duì)一些問題進(jìn)行分析或建立數(shù)學(xué)模型時(shí),從前向后分析問題感到比較棘手,而采用倒推法(如例3),則問題容易理解和解決。下面分別看這幾個(gè)例子:【例1】猴子吃桃問題一只小猴子摘了若干桃子,每天吃現(xiàn)有桃的一半多一個(gè),到第10天時(shí)就只有一個(gè)桃子了,求原有多少個(gè)桃?數(shù)學(xué)模型:每天的桃子數(shù)為:a10=1,a9=(1+a10)*2,a8=(1+a9)*2,……a10=1,遞推公式為:ai=(1+ai+1)*2I=9,8,7,6……1算法如下:
main(){inti,s;s=1;for(i=9;i>=1;i=i-1)s=(s+1)*2print(s);
}【例2】輸出如圖4-1的楊輝三角形(限定用一個(gè)一維數(shù)組完成)。數(shù)學(xué)模型:上下層規(guī)律較明顯,中間的數(shù)等于上行左上、右上兩數(shù)之和。問題分析:題目中要求用一個(gè)一維數(shù)組即完成。數(shù)組空間一定是由下標(biāo)從小到大利用的,這樣其實(shí)楊輝三角形是按下圖4-2形式存儲(chǔ)的。若求n層,則數(shù)組最多存儲(chǔ)n個(gè)數(shù)據(jù)。111121133114641
……………
圖4-1楊輝三角形11112113311
4641……………圖4-2楊輝三角形存儲(chǔ)格式
算法設(shè)計(jì):
A[1]=A[i]=1A[j]=A[j]+A[j-1]j=i-1,i-2,……,2i行i-1行i-1行算法如下:main(){intn,i,j,a[100];input(n);print(“1”);print(“換行符”);a[1]=a[2]=1;print(a[1],a[2]);print(“換行符”);for(i=3;i<=n;i=i+1){a[1]=a[i]=1;for(j=i-1,j>1,j=j-1)a[j]=a[j]+a[j-1];
for(j=1;j<=i;j=j+1)print(a[j]);print(“換行符”);}}【例3】穿越沙漠問題用一輛吉普車穿越1000公里的沙漠。吉普車的總裝油量為500加侖,耗油率為1加侖/公里。由于沙漠中沒有油庫,必須先用這輛車在沙漠中建立臨時(shí)油庫。該吉普車以最少的耗油量穿越沙漠,應(yīng)在什么地方建油庫,以及各處的貯油量。
問題分析:
1)先看一簡(jiǎn)單問題:有一位探險(xiǎn)家用5天的時(shí)間徒步橫穿A、B兩村,兩村間是荒無人煙的沙漠,如果一個(gè)人只能擔(dān)負(fù)3天的食物和水,那么這個(gè)探險(xiǎn)家至少雇幾個(gè)人才能順利通過沙漠。
A城雇用一人與探險(xiǎn)家同帶3天食物同行一天,然后被雇人帶一天食物返回,并留一天食物給探險(xiǎn)家,這樣探險(xiǎn)家正好有3天的食物繼續(xù)前行,并于第三天打電話雇B城人帶3天食物出發(fā),第四天會(huì)面他們會(huì)面,探險(xiǎn)家得到一天的食物赴B城。如圖4-3主要表示了被雇用二人的行程。
AB
圖4-3被雇用二人的行程
2)貯油點(diǎn)問題要求要以最少的耗油量穿越沙漠,即到達(dá)終點(diǎn)時(shí),沙漠中的各臨時(shí)油庫和車的裝油量均為0。這樣只能從終點(diǎn)開始向前倒著推解貯油點(diǎn)和貯油量。數(shù)學(xué)模型:根據(jù)耗油量最少目標(biāo)的分析,下面從后向前分段討論。第一段長(zhǎng)度為500公里且第一個(gè)加油點(diǎn)貯油為500加侖。第二段中為了貯備油,吉普車在這段的行程必須有往返。下面討論怎樣走效率高:1)首先不計(jì)方向這段應(yīng)走奇數(shù)次(保證最后向前走)。2)每次向前行進(jìn)時(shí)吉普車是滿載。3)要能貯存夠下一加油點(diǎn)的貯油量,路上耗油又最少。……下圖是滿足以上條件的最佳方案,此段共走3次:第一、二次來回耗油2/3貯油1/3,第三次耗油1/3貯油2/3,所以第二個(gè)加油點(diǎn)貯油為1000加侖。由于每公里耗油率為1加侖,則此段長(zhǎng)度為500/3公里。第三段與第二段思路相同。下圖是一最佳方案此段共走5次:第一、二次來回耗油2/5貯油3/5,第三、四次來回耗油2/5貯油3/5,第五次耗油1/5貯油4/5,第三個(gè)加油點(diǎn)貯油為1500加侖。此段長(zhǎng)度為500/5?!?/p>
500/5公里
<———500/3公里———><———<———500公里第一———>第二———>第三終點(diǎn)<——貯油點(diǎn)(500)<——貯油點(diǎn)(1000)<———貯油點(diǎn)(1500)……圖4-4貯油點(diǎn)及貯油量示意綜上分析,從終點(diǎn)開始分別間隔500,500/3,500/5,500/7,……(公里)設(shè)立貯油點(diǎn),直到總距離超過1000公里。每個(gè)貯油點(diǎn)的油量為500,1000,1500,……。算法設(shè)計(jì):由模型知道此問題并不必用倒推算法解決(只是分析過程用的是倒推法),只需通過累加算法就能解決。變量說明:dis表示距終點(diǎn)的距離,1000-dis則表示距起點(diǎn)的距離,k表示貯油點(diǎn)從后到前的序號(hào)。desert(){intdis,k,oil,k;dis=500;k=1;oil=500;do{
print(“storepoint”,k,”distance”,1000-dis,”oilquantity”,oil);
k=k+1;dis=dis+500/(2*k-1);oil=500*k;}while(dis<1000)
oil=500*(k-1)+(1000-dis)*(2*k-1);
print(“storepoint”,k,”distance”,0,”oilquantity”,oil);
}4.1.3迭代法解方程迭代法解方程的實(shí)質(zhì)是按照下列步驟構(gòu)造一個(gè)序列x0,x1,…,xn,來逐步逼近方程f(x)=0的解:
1)選取適當(dāng)?shù)某踔祒0;
2)確定迭代格式,即建立迭代關(guān)系,需要將方程f(x)=0改寫為x=φ(x)的等價(jià)形式;構(gòu)造序列x0,x1,……,xn,即先求得x1=φ(x0),再求
x2=φ(x1),……如此反復(fù)迭代,就得到一個(gè)數(shù)列x0,
x1,……,xn,若這個(gè)數(shù)列收斂,即存在極值,且函數(shù)
φ(x)連續(xù),則很容易得到這個(gè)極限值
x*就是方程f(x)=0的根。
【例1】迭代法求方程組根
算法說明:方程組解的初值X=(x0,x1,…,xn-1),迭代關(guān)系方程組為:xi=gi(X)(i=0,1,…,n-1),w為解的精度,則算法如下:
for
(i=0;i<n;i++)
x[i]=初始近似根;
do{k=k+1;for
(i=0;i<n;i
y[i]=x[i];
for
(i=0;i<n;i++)
x[i]=gi(X);
for
(i=0;i<n;i++)c=c+fabs(y[i]-x[i]);
}
while
(c>wandk<maxn);
for
(i=0;i<n;i++)
print(i,“變量的近似根是”,x[i]);
}【例2】牛頓迭代法牛頓迭代法又稱為切線法,它比一般的迭代法有更高的收斂速度,如圖4-5所示。首先,選擇一個(gè)接近函數(shù)f(x)零點(diǎn)的x0,計(jì)算相應(yīng)的f(x0)和切線斜率f‘(x0)(這里f’表示函數(shù)f的導(dǎo)數(shù))。然后我們計(jì)算穿過點(diǎn)(x0,f(x0))且斜率為f‘(x0)的直線方程為:和x軸的交點(diǎn)的x坐標(biāo),也就是求如下方程的解:
將新求得交點(diǎn)的x坐標(biāo)命名為x1。如圖4-5所示,通常x1會(huì)比x0更接近方程f(x)=0的解。接下來用x1開始下一輪迭代
.圖4-5牛頓迭代法
示意圖迭代公式可化簡(jiǎn)為:此公式就是有名的牛頓迭代公式。已經(jīng)證明,如果f‘是連續(xù)的,并且待求的零點(diǎn)x是孤立的,那么在零點(diǎn)x周圍存在一個(gè)區(qū)域,只要初始值x0位于這個(gè)鄰近區(qū)域內(nèi),那么牛頓法必定收斂。
下面給出用牛頓迭代法,求形如ax3+bx2+cx+d=0方程根的算法,系數(shù)a、b、c、d的值依次為1、2、3、4,由主函數(shù)輸入。求x在1附近的一個(gè)實(shí)根。求出根后由主函數(shù)輸出。
main(){floata,b,c,d,fx;print("輸入系數(shù)a,b,c,d:");
input(a,b,c,d);fx=f(a,b,c,d);printf("方程的根為:",fx);}
floatf(a,b,c,d)floata,b,c,d;{floatx1=1,x0,f0,f1;do{x0=x1;
f0=((a*x0+b)*x0+c)*x0+d;
f1=(3*a*x0+2*b)*x0+c;
x1=x0-f0/f1;
}while(fabs(x1-x0)>=1e-4);
return(x1);}
令[a0,b0]=[a,b],c0=(a0+b0)/2,若f(c0)=0,則c0為方程f(x)=0的根;否則,若f(a0)與f(c0)異號(hào),即f(a0)*f(c0)<0,則令[a1,b1]=[a0,c0];若f(b0)與f(c0)異號(hào),即f(b0)*f(c0)<0,則令[a1,b1]=[c0,b0]。依此做下去,當(dāng)發(fā)現(xiàn)f(cn)=0時(shí),或區(qū)間[an,bn]足夠小,比如|an-bn|<0.0001時(shí),就認(rèn)為找到了方程的根。
用二分法求一元非線性方程f(x)=x^3/2+2x^2-8=0(其中^表示冪運(yùn)算)在區(qū)間[0,2]上的近似實(shí)根r,精確到0.0001.算法如下:
圖4-6二分法求解方程示意【例3】二分法求解方程f(x)=0根用二分法求解方程f(x)=0根的前提條件是:f(x)在求解的區(qū)間[a,b]上是連續(xù)的,且已知f(a)與f(b)異號(hào),即f(a)*f(b)<0。main(){floatx,x1=0,x2=2,f1,f2,f;print(“inputa,b(f(a)*f(b)<0)”);input(a,b);f1=x1*x1*x1/2+2*x1*x1-8;f2=x2*x2*x2/2+2*x2*x2-8;
if(f1*f2>0){printf("Noroot");return;}do{x=(x1+x2)/2;
f=x*x*x/2+2*x*x-8;if(f=0)break;if(f1*f>0.0){x1=x;f1=x1*x1*x1/2+2*x1*x1-8;}elsex2=x;}while(fabs(f)>=1e-4);print("root=",x);}4.2蠻力法4.2.1枚舉法4.2.2其它范例
蠻力法是基于計(jì)算機(jī)運(yùn)算速度快這一特性,在解決問題時(shí)采取的一種“懶惰”的策略。這種策略不經(jīng)過(或者說是經(jīng)過很少的)思考,把問題的所有情況或所有過程交給計(jì)算機(jī)去一一嘗試,從中找出問題的解。蠻力策略的應(yīng)用很廣,具體表現(xiàn)形式各異,數(shù)據(jù)結(jié)構(gòu)課程中學(xué)習(xí)的:選擇排序、冒泡排序、插入排序、順序查找、樸素的字符串匹配等,都是蠻力策略具體應(yīng)用。比較常用還有枚舉法、盲目搜索算法等,本節(jié)介紹枚舉法和其它一些小的范例,第五章介紹盲目搜索算法。
4.2.1枚舉法
枚舉(
enumerate)法(窮舉法)是蠻力策略的一種表現(xiàn)形式,也是一種使用非常普遍的思維方法。它是根據(jù)問題中的條件將可能的情況一一列舉出來,逐一嘗試從中找出滿足問題條件的解。但有時(shí)一一列舉出的情況數(shù)目很大,如果超過了我們所能忍受的范圍,則需要進(jìn)一步考慮,排除一些明顯不合理的情況,盡可能減少問題可能解的列舉數(shù)目。用枚舉法解決問題,通??梢詮膬蓚€(gè)方面進(jìn)行算法設(shè)計(jì):
1)找出枚舉范圍:分析問題所涉及的各種情況。
2)找出約束條件:分析問題的解需要滿足的條件,并用邏輯表達(dá)式表示?!纠?】百錢百雞問題。中國古代數(shù)學(xué)家張丘建在他的《算經(jīng)》中提出了著名的“百錢百雞問題”:雞翁一,值錢五;雞母一,值錢三;雞雛三,值錢一;百錢買百雞,翁、母、雛各幾何?算法設(shè)計(jì)1:通過對(duì)問題的理解,讀者可能會(huì)想到列出兩個(gè)三元一次方程,去解這個(gè)不定解方程,就能找出問題的解。這確實(shí)是一種辦法,但這里我們要用“懶惰”的枚舉策略進(jìn)行算法設(shè)計(jì):
設(shè)x,y,z分別為公雞、母雞、小雞的數(shù)量。嘗試范圍:由題意給定共100錢要買百雞,若全買公雞最多買100/5=20只,顯然x的取值范圍1~20之間;同理,y的取值范圍在1~33之間,z的取值范圍在1~100之間。約束條件:
x+y+z=100且
5*x+3*y+z/3=100
算法1如下:
main()
{intx,y,z;
for(x=1;x<=20;x=x+1)
for(y=1;y<=34;y=y+1)
for(z=1;z<=100;z=z+1)
if(100=x+y+zand100=5*x+3*y+z/3)
{print(thecocknumberis",x);
print(thehennumberis",y);print(thechicknumberis"z);}
}算法分析:以上算法需要枚舉嘗試20*34*100=68000次。算法的效率顯然太低算法設(shè)計(jì)2:在公雞(x)、母雞(y)的數(shù)量確定后,小雞
的數(shù)量
z就固定為100-x-y,無需再進(jìn)行枚舉了
此時(shí)約束條件只有一個(gè):
5*x+3*y+z/3=100
算法2如下:
main()
{
intx,y,z;
for(x=1;x<=20;x=x+1)
for(y=1;y<=33;y=y+1)
{
z=100-x-y;
if(zmod3=0and5*x+3*y+z/3=100)
{print(thecocknumberis",x);
print(thehennumberis",y);print(thechicknumberis"z);}
}
}算法分析:以上算法只需要枚舉嘗試20*33=660次。實(shí)現(xiàn)時(shí)約束條件又限定Z能被3整除時(shí),才會(huì)判斷“5*x+3*y+z/3=100”。這樣省去了z不整除3時(shí)的算術(shù)計(jì)算和條件判斷,進(jìn)一步提高了算法的效率?!纠?】解數(shù)字迷:ABCAB
×ADDDDDD算法設(shè)計(jì)1:按乘法枚舉1)枚舉范圍為:
A:3——9(A=1,2時(shí)積不會(huì)得到六位數(shù)),B:0——9,C:0——9六位數(shù)表示為A*10000+B*1000+C*100+A*10+B,共嘗試800次。2)約束條件為:每次嘗試,先求六位數(shù)與A的積,再測(cè)試積的各位是否相同,若相同則找到了問題的解。測(cè)試積的各位是否相同比較簡(jiǎn)單的方法是,從低位開始,每次都取數(shù)據(jù)的個(gè)位,然后整除10,使高位的數(shù)字不斷變成個(gè)位,并逐一比較。
算法1如下:main(){intA,B,C,D,E,E1,F,G1,G2,i;for(A=3;A<=9;A++)
for(B=0;B<=9;B++)for(C=0;C<=9;C++){F=A*10000+B*1000+C*100+A*10+B;E=F*A;E1=E;G1=E1mod10;for(i=1;i<=5;i++){G2=G1;E1=E1/10;G1=E1mod10;if(G1<>G2)break;}
if(i=6)print(F,”*”,A,”=”,E);
}}算法說明1:算法中對(duì)枚舉出的每一個(gè)五位數(shù)與A相乘,結(jié)果存儲(chǔ)在變量E中。然后,測(cè)試得到的六位數(shù)E是否各個(gè)位的數(shù)字都相同。鑒于要輸出結(jié)果,所以不要改變計(jì)算結(jié)果,而另設(shè)變量E1,用于測(cè)試運(yùn)算。算法分析1:以上算法的嘗試范圍是A:3——9,B:0——9,C:0——9。共嘗試800次,每次,不是一個(gè)好的算法。算法設(shè)計(jì)2:將算式變形為除法:DDDDDD/A=ABCAB。此時(shí)只需枚舉A:3——9D:1——9,共嘗試7*9=63次。每次嘗試,測(cè)試商的萬位、十位與除數(shù)是否相同,千位與個(gè)位是否相同,都相同時(shí)為解。算法2如下:main(){intA,B,C,D,E,F;for(A=3;A<=9;A++)for(D=1;D<=9;D++){E=D*100000+D*10000+D*1000+D*100+D*10+D;
if(EmodA=0)F=E\A;
if(F\10000=Aand(Fmod100)\10=A)if(F\1000==Fmod10)print(F,”*”,A,”=”,E);}}
蠻力法的表現(xiàn)形式非常多,如第三章3.2.4例題、3.2.5例1及本章下一節(jié)4.3.3例4的算法1等。本節(jié)將通過蠻力策略,用算法模擬問題中所描述的全部過程和全部狀態(tài),來找出問題的解,并與經(jīng)過數(shù)學(xué)建模后的算法進(jìn)行效率上的比較。
4.2.2其它范例【例3】獄吏問題某國王對(duì)囚犯進(jìn)行大赦,讓一獄吏n次通過一排鎖著的n間牢房,每通過一次,按所定規(guī)則轉(zhuǎn)動(dòng)n間牢房中的某些門鎖,每轉(zhuǎn)動(dòng)一次,原來鎖著的被打開,原來打開的被鎖上;通過n次后,門鎖開著的,牢房中的犯人放出,否則犯人不得獲釋。轉(zhuǎn)動(dòng)門鎖的規(guī)則是這樣的,第一次通過牢房,要轉(zhuǎn)動(dòng)每一把門鎖,即把全部鎖打開;第二次通過牢房時(shí),從第二間開始轉(zhuǎn)動(dòng),每隔一間轉(zhuǎn)動(dòng)一次;第k次通過牢房,從第k間開始轉(zhuǎn)動(dòng),每隔k-1間轉(zhuǎn)動(dòng)一次;問通過n次后,那些牢房的鎖仍然是打開的?算法設(shè)計(jì)1:1)用n個(gè)空間的一維數(shù)組a[n],每個(gè)元素記錄一個(gè)鎖的狀態(tài),1為被鎖上,0為被打開。2)用數(shù)學(xué)運(yùn)算方便模擬開關(guān)鎖的技巧,對(duì)i號(hào)鎖的一次開關(guān)鎖可以轉(zhuǎn)化為算術(shù)運(yùn)算:a[i]=1-a[i]。3)第一次轉(zhuǎn)動(dòng)的是1,2,3,……,n號(hào)牢房;第二次轉(zhuǎn)動(dòng)的是2,4,6,……號(hào)牢房;第三次轉(zhuǎn)動(dòng)的是3,6,9,……號(hào)牢房;
……第i次轉(zhuǎn)動(dòng)的是i,2i,3i,4i,……號(hào)牢房,是起點(diǎn)為i,公差為i的等差數(shù)列。
4)不做其它的優(yōu)化,用蠻力法通過循環(huán)模擬獄吏的開關(guān)鎖過程,最后當(dāng)?shù)趇號(hào)牢房對(duì)應(yīng)的數(shù)組元素a[i]為0時(shí),該牢房的囚犯得到大赦。算法1如下:
main1(){int*a,i,j,n;input(n);a=calloc(n+1,sizeof(int));for(i=1;i<=n;i++)a[i]=1;for(i=1;i<=n;i++)for(j=i;j<=n;j=j+i)a[i]=1-a[i];for(i=1;i<=n;i++)if(a[i]=0)print(i,”isfree.”);}算法分析:以一次開關(guān)鎖計(jì)算,算法的時(shí)間復(fù)雜度為n(1+1/2+1/3+……+1/n)=O(nlogn)。問題分析:轉(zhuǎn)動(dòng)門鎖的規(guī)則可以有另一種理解,第一次轉(zhuǎn)動(dòng)的是編號(hào)為1的倍數(shù)的牢房;第二次轉(zhuǎn)動(dòng)的是編號(hào)為2的倍數(shù)的牢房;第三次轉(zhuǎn)動(dòng)的是編號(hào)為3的倍數(shù)的牢房;……則獄吏問題是一個(gè)關(guān)于因子個(gè)數(shù)的問題。令d(n)為自然數(shù)n的因子個(gè)數(shù),這里不計(jì)重復(fù)的因子,如4的因子為1,2,4共三個(gè)因子,而非1,2,2,4。則d(n)有的為奇數(shù),有的為偶數(shù),見下表:
表4-3編號(hào)與因數(shù)個(gè)數(shù)的關(guān)系
n12345678910111213141516……d(n)1223242434262445……
數(shù)學(xué)模型1:上表中的d(n)有的為奇數(shù),有的為偶數(shù),由于牢房的門開始是關(guān)著的,這樣編號(hào)為i的牢房,所含1——i之間的不重復(fù)因子個(gè)數(shù)為奇數(shù)時(shí),牢房最后是打開的,反之,牢房最后是關(guān)閉的。算法設(shè)計(jì)2:
1)算法應(yīng)該是求出每個(gè)牢房編號(hào)的不重復(fù)的因子個(gè)數(shù),當(dāng)它為奇數(shù)時(shí),這里邊的囚犯得到大赦。2)一個(gè)數(shù)的因子是沒有規(guī)律的,只能從1——n枚舉嘗試。算法2如下:main2(){ints,i,j,n;input(n);for(i=1;i<=n;i++){s=1;for(j=2;j<=i;j=j++)if(imodj=0)s=s+1;if(smod2=1)print(i,”isfree.”);}}算法分析:獄吏開關(guān)鎖的主要操作是a[i]=1-a[i];共執(zhí)行了n*(1+1/2+1/3+……+1/n)次,時(shí)間近似為復(fù)雜度為O(nlogn)。使用了n個(gè)空間的一維數(shù)組。算法2沒有使用輔助空間,但由于求一個(gè)編號(hào)的因子個(gè)數(shù)也很復(fù)雜,其主要操作是判斷imodj是否為0,共執(zhí)行了n*(1+2+3+……+n)次,時(shí)間復(fù)雜度為O(n2)。
數(shù)學(xué)模型2:仔細(xì)觀察表4-3,發(fā)現(xiàn)當(dāng)且僅當(dāng)n為完全平方數(shù)時(shí),d(n)為奇數(shù);這是因?yàn)閚的因子是成對(duì)出現(xiàn)的,也即當(dāng)n=a*b且a≠b時(shí),必有兩個(gè)因子a,b;只有n為完全平方數(shù),也即當(dāng)n=a2時(shí),才會(huì)出現(xiàn)d(n)為奇數(shù)的情形。算法設(shè)計(jì)3:這時(shí)只需要找出小于n的平方數(shù)即可。算法3如下:main3(){ints,i,j,n;input(n);for(i=1;i<=n;i++)if(i*i<=n)print(i,”isfree.”);elsebreak;}
由此算法我們應(yīng)當(dāng)注意:在對(duì)運(yùn)行效率要求較高的大規(guī)模的數(shù)據(jù)處理問題時(shí),必須多動(dòng)腦筋找出效率較高的數(shù)學(xué)模型及其對(duì)應(yīng)的算法。4.3分而治之算法4.3.1分治算法框架4.3.2二分法4.3.3二分法變異4.3.4其它分治方法4.3.1分治算法框架
1.算法設(shè)計(jì)思想分治法求解問題的過程是,將整個(gè)問題分解成若干個(gè)小問題后分而治之。如果分解得到的子問題相對(duì)來說還太大,則可反復(fù)使用分治策略將這些子問題分成更小的同類型子問題,直至產(chǎn)生出方便求解的子問題,必要時(shí)逐步合并這些子問題的解,從而得到問題的解。分治法的基本步驟在每一層遞歸上都有三個(gè)步驟:1)分解:將原問題分解為若干個(gè)規(guī)模較小,相互獨(dú)立,與原問題形式相同的子問題;
2)解決:若子問題規(guī)模較小而容易被解決則直接解,否則再繼續(xù)分解為更小的子問題,直到容易解決;
3)合并:將已求解的各個(gè)子問題的解,逐步合并為原問題的解。有時(shí)問題分解后,不必求解所有的子問題,也就不必作第三步的操作。比如折半查找,在判別出問題的解在某一個(gè)子問題中后,其它的子問題就不必求解了,問題的解就是最后(最?。┑淖訂栴}的解。分治法的這類應(yīng)用,又稱為“減治法”。多數(shù)問題需要所有子問題的解,并由子問題的解,使用恰當(dāng)?shù)姆椒ê喜⒊蔀檎麄€(gè)問題的解,比如合并排序,就是不斷將子問題中已排好序的解合并成較大規(guī)模的有序子集。
2.適合用分治法策略的問題當(dāng)求解一個(gè)輸入規(guī)模為n且取值又相當(dāng)大的問題時(shí),用蠻力策略效率一般得不到保證。若問題能滿足以下幾個(gè)條件,就能用分治法來提高解決問題的效率。1)
能將這n個(gè)數(shù)據(jù)分解成k個(gè)不同子集合,且得到k個(gè)子集合是可以獨(dú)立求解的子問題,其中1<k≤n;2)
分解所得到的子問題與原問題具有相似的結(jié)構(gòu),便于利用遞歸或循環(huán)機(jī)制;在求出這些子問題的解之后,就可以推解出原問題的解;
分治法的一般的算法設(shè)計(jì)模式如下:Divide-and-Conquer(intn)/n為問題規(guī)模/{if(n≤n0)/n0為可解子問題的規(guī)模/
{解子問題;
return(子問題的解);}for(i=1;i<=k;i++)/分解為較小子問題p1,p2,……pk/
yi=Divide-and-Conquer(|Pi|);/遞歸解決Pi/
T=MERGE(y1,y2,...,yk);/合并子問題/return(T);}
其中|P|表示問題P的規(guī)模;n0為一閾值,表示當(dāng)問題P的規(guī)模不超過n0時(shí),問題已容易直接解出,不必再繼續(xù)分解。算法MERGE(y1,y2,...,yk)是該分治法中的合并子算法,用于將P的子問題P1,P2,...,Pk的相應(yīng)的解y1,y2,...,yk合并為P的解。在一些問題中不需要這一步。如析半查找、4.3.2中的例1、例2等。4.3.2二分法
不同于現(xiàn)實(shí)中對(duì)問題(或工作)的分解,可能會(huì)考慮問題(或工作)的重點(diǎn)、難點(diǎn)、承擔(dān)人員的能力等來進(jìn)行問題的分解和分配。在算法設(shè)計(jì)中每次一個(gè)問題分解成的子問題個(gè)數(shù)一般是固定的,每個(gè)子問題的規(guī)模也是平均分配的。當(dāng)每次都將問題分解為原問題規(guī)模的一半時(shí),稱為二分法。二分法是分治法較常用的分解策略,數(shù)據(jù)結(jié)構(gòu)課程中的折半查找、歸并排序等算法都是采用此策略實(shí)現(xiàn)的。【例1】金塊問題:老板有一袋金塊(共n塊),最優(yōu)秀的雇員得到其中最重的一塊,最差的雇員得到其中最輕的一塊。假設(shè)有一臺(tái)比較重量的儀器,我們希望用最少的比較次數(shù)找出最重的金塊。算法設(shè)計(jì)1:比較簡(jiǎn)單的方法是逐個(gè)的進(jìn)行比較查找。先拿兩塊比較重量,留下重的一個(gè)與下一塊比較,直到全部比較完畢,就找到了最重的金子。算法類似于一趟選擇排序,算法如下:
maxmin(floata[],intn){max==min=a[1];
for(i=2i<=ni++)
if(max<a[i])max=a[i];elseif(min>a[i])min=a[i];
}算法分析1:算法中需要n-1次比較得到max。最好的情況是金塊是由小到大取出的,不需要進(jìn)行與min的比較,共進(jìn)行n-1次比較。最壞的情況是金塊是由大到小取出的,需要再經(jīng)過n-1次比較得到min,共進(jìn)行2*n-2次比較。至于在平均情況下,A(i)將有一半的時(shí)間比max大,因此平均比較數(shù)是3(n—1)/2。
算法設(shè)計(jì)2:問題可以簡(jiǎn)化為:在含n(n是2的冪(n>=2))個(gè)元素的集合中尋找極大元和極小元。用分治法(二分法)可以用較少比較次數(shù)地解決上述問題:1)
將數(shù)據(jù)等分為兩組(兩組數(shù)據(jù)可能差1),目的是分別選取其中的最大(?。┲?。2)
遞歸分解直到每組元素的個(gè)數(shù)≤2,可簡(jiǎn)單地找到最大(?。┲?。3)
回溯時(shí)將分解的兩組解大者取大,小者取小,合并為當(dāng)前問題的解。
算法2
遞歸求取最大和最小元素floata[n];maxmin
(inti,intj,float&fmax,float&fmin){intmid;floatlmax,lmin,rmax,rmin;if(i=j){fmax=a[i];fmin=a[i];}elseif(i=j-1)if(a[i]<a[j]){fmax=a[j];fmin=a[i];}
else{fmax=a[i];fmin=a[j];}else{mid=(i+j)/2;
maxmin
(i,mid,lmax,lmin);
maxmin
(mid+1,j,rmax,rmin);
if(lmax>rmax)fmax=lmax;elsefmax=rmax;
if(lmin>rmin)fmin=rmin;elsefmin=lmin;
}
算法分析:MAXMIN需要的元素比較數(shù)是多少呢?如果用T(n)表示這個(gè)數(shù),則所導(dǎo)出的遞歸關(guān)系式是:
當(dāng)n是2的冪時(shí),即對(duì)于這個(gè)某個(gè)正整數(shù)k,n=2k,有
可以證明,任何以元素比較為基礎(chǔ)的找最大和最小元素的算法,其元素比較下界均為次。因此,過程MAXMIN在這種意義上是最優(yōu)的?!纠?】殘缺棋盤殘缺棋盤是一個(gè)有2k×2k
(k≥1)個(gè)方格的棋盤,其中恰有一個(gè)方格殘缺。圖4-7給出k=1時(shí)各種可能的殘缺棋盤,其中殘缺的方格用陰影表示。
①號(hào)②號(hào)③號(hào)④號(hào)圖4-7四種三格板這樣的棋盤我們稱作“三格板”,殘缺棋盤問題就是要用這四種三格板覆蓋更大的殘缺棋盤。在此覆蓋中要求:1)兩個(gè)三格板不能重疊2)三格板不能覆蓋殘缺方格,但必須覆蓋其他所有的方格在這種限制條件下,所需要的三格板總數(shù)為(2k×2k
-1)/3。
算法設(shè)計(jì)1:下面用分而治之方法解決殘缺棋盤問題。1)問題分解過程如下:以k=2時(shí)的問題為例,用二分法進(jìn)行分解,得到的是如下圖4-8,用雙線劃分的四個(gè)k=1的棋盤。但要注意這四個(gè)棋盤,并不都是與原問題相似且獨(dú)立的子問題。因?yàn)楫?dāng)如圖4-8中的殘缺方格在左上部時(shí),第1個(gè)子問題與原問題相似,而右上角、左下角和右下角三個(gè)子棋盤(也就是圖中標(biāo)識(shí)為2、3、4號(hào)子棋盤),并不是原問題的相似子問題,自然也就不能獨(dú)立求解了。當(dāng)使用一個(gè)①號(hào)三格板(圖中陰影)覆蓋2、3、4號(hào)三個(gè)子棋盤的各一個(gè)方格后,如4-8右圖所示,我們把覆蓋后的方格,也看作是殘缺方格(稱為“偽”殘缺方格),這時(shí)的2、3、4號(hào)子問題就是獨(dú)立且與原問題相似的子問題了。
圖4-8一個(gè)4*4的殘缺棋盤從以上例子還可以發(fā)現(xiàn),當(dāng)殘缺方格在第1個(gè)子棋盤,用①號(hào)三格板覆蓋其余三個(gè)子棋盤的交界方格,可以使另外三個(gè)子棋盤轉(zhuǎn)化為獨(dú)立子問題;同樣地(如下圖4-9所示),當(dāng)殘缺方格在第2個(gè)子棋盤時(shí),則首先用②號(hào)三格板進(jìn)行棋盤覆蓋,當(dāng)殘缺方格在第3個(gè)子棋盤時(shí),則首先用③號(hào)三格板進(jìn)行棋盤覆蓋,當(dāng)殘缺方格在第4個(gè)子棋盤時(shí),則首先用④號(hào)三格板進(jìn)行棋盤覆蓋,這樣就使另外三個(gè)子棋盤轉(zhuǎn)化為獨(dú)立子問題。如下圖4-9:同樣地k=1,2,3,4……都是如此,k=1為停止條件。
圖4-9其它4*4的殘缺棋盤2)棋盤的識(shí)別棋盤的規(guī)模是一個(gè)必要的信息,有了這個(gè)信息,只要知道其左上角的左上角方格所在行、列就可以唯一確定一個(gè)棋盤了,殘缺方格或“偽”殘缺方格直接用行、列號(hào)記錄。?
tr棋盤中左上角方格所在行。?
tc棋盤中左上角方格所在列。?
dr殘缺方塊所在行。?dl殘缺方塊所在列。?size棋盤的行數(shù)或列數(shù)。數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì):用二維數(shù)組board[][],模擬棋盤。覆蓋殘缺棋盤所需要的三格板數(shù)目為:(size2-1)/3將這些三格板編號(hào)為1到(size2-1)/3。則將殘缺棋盤三格板編號(hào)的存儲(chǔ)在數(shù)組board[][]的對(duì)應(yīng)位置中,這樣輸出數(shù)組內(nèi)容就是問題的解。結(jié)合圖4-9,理解算法。算法如下:
intamount=0;main(){intsize=1,x,y;input(k);for(i=1;i<=k;i++)size=size*2;
print(“inputincompletepane”);input(x,y);
Cover(0,0,x,y,size);}圖4-9
一個(gè)4*4的殘缺棋盤及其解
Cover(inttr,inttc,intdr,intdc,intsize){if(size<2)return;intt=amount++,//所使用的三格板的數(shù)目s=size/2;
//子問題棋盤大小
if(dr<tr+s&&dc<tc+s)//殘缺方格位于左上棋盤{Cover(tr,tc,dr,dc,s);
Board[tr+s-1][tc+s]=t;
//覆蓋1號(hào)三格板
Board[tr+s][tc+s-1]=t;
Board[tr+s][tc+s]=t;
Cover(tr,tc+s,tr+s-1,tc+s,s);//覆蓋其余部分
Cover(tr+s,tc,tr+s,tc+s-1,s);
Cover(tr+s,tc+s,tr+s,tc+s,s);
}elseif(dr<tr+s&&dc>=tc+s)//殘缺方格位于右上象限{Cover(tr,tc+s,dr,dc,s);
Board[tr+s-1][tc+s-1]=t;//覆蓋2號(hào)三格板
Board[tr+s][tc+s-1]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);//覆蓋其余部分
Cover(tr+s,tc,tr+s,tc+s-1,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}elseif(dr>=tr+s&&dc<tc+s)//殘缺方格位于覆蓋左下象限{Cover(tr+s,tc,dr,dc,s);
Board[tr+s-1][tc+s-1]=t;
//覆蓋3號(hào)三格板
Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);
//覆蓋其余部分
Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}elseif(dr>=tr+s&&dc>=tc+s)
//殘缺方格位于右下象限{Cover(tr+s,tc+s,dr,dc,s);
Board[tr+s-1][tc+s-1]=t;
//覆蓋4號(hào)三格板
Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s-1]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);
//覆蓋其余部分
Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc,tr+s,tc+s-1,s);}}voidOutputBoard(intsize){for(inti=0;i<size;i++)
{for(intj=0;j<size;j++)print(Board[i][j]);
print(“換行符”);}}算法分析:因?yàn)橐采w(size2-1)/3個(gè)三格板,所以算法的時(shí)間復(fù)雜性為O(size2)。
4.3.3二分法變異
【例3】求最長(zhǎng)連續(xù)不升數(shù)列有一組數(shù)據(jù)找出其中最長(zhǎng)的連續(xù)不升數(shù)列算法設(shè)計(jì):此問題用二分法分解后的兩個(gè)子序列(子問題)并不獨(dú)立,因?yàn)橛锌赡茏铋L(zhǎng)的連續(xù)不升數(shù)列正好存在于兩個(gè)子序列的連接位置。如果將所給的序列a[1..n]分為長(zhǎng)度相等的2段
a[1——(n/2)]和a[(n/2)+1——n],則a[1.n]的最長(zhǎng)連續(xù)不升數(shù)列有3種情況:
問題分析:若用二分法將實(shí)例中的數(shù)據(jù)分解為兩組(-2,11,-4),(13,-5,-2),第一個(gè)子問題的解是11,第二個(gè)子問題的解是13,兩個(gè)子問題的解不能簡(jiǎn)單地得到原問題的解。由此看出這個(gè)問題不能分解用二分法成解為獨(dú)立的兩個(gè)子問題,子問題中間還有公共的子問題,這類問題稱為子問題重疊類的問題。那么,怎樣解決這類問題呢?雖沒有通用的方法,但本章4.5節(jié)的介紹的動(dòng)態(tài)規(guī)劃算法是一種較好的解決方法。下面我們?nèi)杂枚址ń鉀Q這類問題中的一些簡(jiǎn)單問題,學(xué)習(xí)一下如何處理不獨(dú)立的子問題。算法設(shè)計(jì):分解方法和上面的例題一樣采用二分法,雖然分解后的子問題并不獨(dú)立,但通過對(duì)重疊的子問題進(jìn)行專門處理,并對(duì)所有子問題合并進(jìn)行設(shè)計(jì),就可以用二分策略解決此題。
如果將所給的序列a[1..n]分為長(zhǎng)度相等的2段a[1——(n/2)]和a[(n/2)+1——n],分別求出這2段的最大子段和,則a[1.n]的最大子段和有3種情形。1)a[1..n]的最長(zhǎng)連續(xù)不升數(shù)列與a[1..(n/2)]的最長(zhǎng)連續(xù)不升數(shù)列相同;2)a[1..n]的最長(zhǎng)連續(xù)不升數(shù)列與a[(n/2)+1..n]的最長(zhǎng)連續(xù)不升數(shù)列相同;3)a[1..n]的最長(zhǎng)連續(xù)不升數(shù)列為∑a[k],且
1≤i≤(n/2),(n/2),(n/2)+1≤j≤n。情況1)和情況2)可分別遞歸求得。對(duì)于情況3),a[(n/2)]與a[(n/2)+1]一定在最優(yōu)子序列中。因此,我們可以計(jì)算出a[i..(n/2)]的最大值s1;并計(jì)算出a[(n/2)+1..j]中的最大值s2。則s1+s2即為出現(xiàn)情況3)時(shí)的最優(yōu)值。算法如下:intmax_sum3(inta[],intn){return(max_sub_sum(a,1,n));}max_sub_sum(inta[],intleft,intright){intcenter,i,j,sum,left_sum,right_sum,s1,s2,lefts,rights;if(left=right)
if(a[left]>0)return(a[left]);
elsereturn(0);else{center=(left+right)/2;left_sum=max_sub_sum(a,left,center);right_sum=max_sub_sum(a,center+1,right);s1=0;/處理情形3/lefts=0;for(i=center;i>=left;i--)
{lefts=lefts+a[i];if(lefts>s1)s1=lefts;}s2=0;rights=0;for(i=center+1;i<=right;i++)
{rights=rights+a[i];
if(rights>s2)s2=rights;}if(s1+s2<left_sumandright_sum<left_sum)rturn(left_sum);if(s1+s2<right_sum)return(right_sum);return(s1+s2);}}【例4】大整數(shù)乘法在某些情況下,我們需要處理很大的整數(shù),它無法在計(jì)算機(jī)硬件能直接允許的范圍內(nèi)進(jìn)行表示和處理。若用浮點(diǎn)數(shù)來存儲(chǔ)它,只能近似地參與計(jì)算,計(jì)算結(jié)果的有效數(shù)字會(huì)受到限制。若要精確地表示大整數(shù),并在計(jì)算結(jié)果中要求精確地得到所有位數(shù)上的數(shù)字,就必須用軟件的方法來實(shí)現(xiàn)大整數(shù)的算術(shù)運(yùn)算。請(qǐng)?jiān)O(shè)計(jì)一個(gè)有效的算法,可以進(jìn)行兩個(gè)n位大整數(shù)的乘法運(yùn)算。數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì):首先用數(shù)組存儲(chǔ)大整數(shù)數(shù)據(jù),再將兩個(gè)乘數(shù)和積都按由低位到高位逐位存儲(chǔ)到數(shù)組元素中。算法設(shè)計(jì)1:存儲(chǔ)好兩個(gè)高精度數(shù)據(jù)后,模擬豎式乘法,讓兩個(gè)高精度數(shù)據(jù)的按位交叉相乘,并逐步累加即可得到精確的結(jié)果,用二重循環(huán)就可實(shí)現(xiàn)。
算法設(shè)計(jì)1:存儲(chǔ)好兩個(gè)高精度數(shù)據(jù)后,我們模擬豎式乘法,讓兩個(gè)高精度數(shù)據(jù)的按位交叉相乘,并逐步累加,即可得到精確的計(jì)算結(jié)果。用二重循環(huán)就可控制兩個(gè)數(shù)不同位相乘的過程。只考慮正整數(shù)的乘法,算法細(xì)節(jié)設(shè)計(jì)如下:1)對(duì)于大整數(shù)比較方便的輸入方法是,按字符型處理,存儲(chǔ)在字符串?dāng)?shù)組s1、s2中,計(jì)算結(jié)果存儲(chǔ)在整型數(shù)組a中。2)通過字符的ASCII碼,數(shù)字字符可以直接參與運(yùn)算,k位數(shù)字與j位數(shù)字相乘的表達(dá)式為:s1[k]-48)*(s2[j]-48)。這是C語言的處理方法,其它程序設(shè)計(jì)語言有對(duì)應(yīng)的函可以實(shí)現(xiàn)數(shù)字字符與數(shù)字的轉(zhuǎn)換,這里不詳細(xì)介紹了。3)每一次數(shù)字相乘的結(jié)果位數(shù)是不固定的,而結(jié)果數(shù)組中每個(gè)元素只存儲(chǔ)一位數(shù)字,所以用變量b暫存結(jié)果,若超過1位數(shù)則進(jìn)位,用變量d存儲(chǔ)。這樣每次計(jì)算的表達(dá)式為:
b=a[i]+(s1[k]-48)*(s2[j]-48)+d;。main(){longb,c,d;inti,i1,i2,j,k,n,n1,n2,a[256];
chars1[256],s2[256];
input(s1);input(s2);for(i=0;i<255;i++)a[i]=0;n1=strlen(s1);n2=strlen(s2);d=0;for(i1=0,k=n1-1;i1<n1;i1++,k--){for(i2=0,j=n2-1;i2<n2;i2++,j--){i=i1+i2;b=a[i]+(s1[k]-48)*(s2[j]-48)+d;a[i]=bmod10;d=b/10;}
while(d>0){i=i+1;a[i]=a[i]+dmod10;d=d/10;}n=i;}for(i=n;i>=0;i--)print(a[i]);}算法說明:循環(huán)變量j、k分別是兩個(gè)乘數(shù)字符串的下標(biāo)。i1表示字符串str1由低位到高位的位數(shù),范圍0——n1-1(與k相同)。i2表示字符串str2由低位到高位的位數(shù),范圍0——n2-1(與j相同)。i表示乘法正在運(yùn)算的位,也是計(jì)算結(jié)果存儲(chǔ)的位置。算法分析1:算法是以n1,n2代表兩個(gè)乘數(shù)的位數(shù),由算法中的循環(huán)嵌套知,算法的主要操作是乘法,算法的時(shí)間復(fù)雜度是O(n1*n2)。
算法設(shè)計(jì)2:下面?zhèn)冇梅种畏▉碓O(shè)計(jì)一個(gè)更有效的大整數(shù)乘積算法。設(shè)計(jì)的重點(diǎn)是要提高乘法算法的效率,設(shè)計(jì)如下:
設(shè)X和Y都是n位的二進(jìn)制整數(shù),現(xiàn)在要計(jì)算它們的乘積X*Y。圖4-10大整數(shù)X和Y的分段
將n位的二進(jìn)制整數(shù)X和Y各分為2段,每段的長(zhǎng)為n/2位(為簡(jiǎn)單起見,假設(shè)n是2的冪),如圖4-10所示。顯然問題的答案并不是A*C*K1+C*D*K2(K1、K2與A、B、C、D無關(guān)),也就是說,這樣做并沒有將問題分解成兩個(gè)獨(dú)立的子問題。按照乘法分配律,分解后的計(jì)算過程如下:記:X=A*2n/2+B,Y=C*2n/2+D。這樣,X和Y的乘積為:X*Y=(A*2n/2+B)(C*2n/2+D)=A*C*2n+(AD+CB)*2n/2+B*D
(1)模型分析:如果按式(1)計(jì)算X*Y,則我們必須進(jìn)行4次n/2位整數(shù)的乘法(AC,AD,BC和BD),以及3次不超過n位的整數(shù)加法,此外還要做2次移位(分別對(duì)應(yīng)于式(1)中乘2n和乘2n/2)。所有這些加法和移位共用O(n)步運(yùn)算。設(shè)T(n)是2個(gè)n位整數(shù)相乘所需的運(yùn)算總數(shù),則由式(1),我們有以下(2)式:
T(1)=1T(n)=4T(n/2)+O(n)(2)
由此遞歸式迭代過程如下:T(n)=4T(n/2)+cn=4(4T(n/4)+cn/2)+cn=16(T(n/8)+cn/4)+3cn/2+cn=……
=
+4k-1*2c+4k-2*4c+……+4c2k-1+c2k
=O(4k)=O(nlog4)
=O(n2)所以可得算法的時(shí)間復(fù)雜度為T(n)=O(n2)。模型改進(jìn):可以把X*Y寫成另一種形式:X*Y=A*C*2n+[(A-B)(D-C)+AC+BD]*2n/2+B*D
(3)式(3)看起來比式(1)復(fù)雜,但它僅需做3次n/2位整數(shù)的乘法:AC,BD和(A-B)(D-C),6次加、減法和2次移位。由此可得:
(4)
用解遞歸方程的迭代公式法,不妨設(shè)n=2k:
T(n)=3T(n/2)+cn=3(3T(n/4)+cn/2)+cn=9(T(n/8)+cn/4)+3cn/2+cn
=……=3k+3k-1*2c+3k-2*4c+……+3c2k-1+c2k=O(nlog3)則得到T(n)=O(nlog3)=O(n1.59)。MULT(X,Y,n)
{X和Y為2個(gè)小于2n的整數(shù),返回結(jié)果為X和Y的乘積XY}
{S=SIGN(X)*SIGN(Y);//S為X和Y的符號(hào)乘積
X=ABS(X);
Y=ABS(Y);//X和Y分別取絕對(duì)值
if(n=1)
if(X=1andY=1)return(S);
elsereturn(0);
else
{
A=X的左邊n/2位;B=X的右邊n/2位;
C=Y的左邊n/2位;D=Y的右邊n/2位;
ml=MULT(A,C,n/2);m2=MULT(A-B,D-C,n/2);
m3=MULT(B,D,n/2);
S=S*(m1*2n+(m1+m2+m3)*2n/2+m3);
return(S);}
}4.3.4其它分治方法
以上的例子都是用二分策略把問題分解為與原問題相似“相等”的子問題。下面看幾個(gè)用“非等分二分法”解決問題的例子。選擇問題就是“從一組數(shù)中選擇的第k小的數(shù)據(jù)”,這個(gè)問題的一個(gè)應(yīng)用就是尋找中值元素,此時(shí)k=[n/2]。中值是一個(gè)很有用的統(tǒng)計(jì)量,例如中間工資,中間年齡,中間重量等。k取其他值也是有意義的,例如,通過尋找第k=n/2、k=n/3和k=n/4的年齡,可將人口進(jìn)行劃分,了解人口的分布情況。這個(gè)問題可以通過排序來解決,但根據(jù)《數(shù)據(jù)結(jié)構(gòu)》課程的經(jīng)驗(yàn),最好的排序算法的復(fù)雜性也是O(n*log(n)),下面我們要利用分治法,找到復(fù)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 屋面光伏支架預(yù)埋施工方案
- 河南大型水景施工方案
- 邯鄲水泥板圍墻施工方案
- 安徽省天一大聯(lián)考2025屆高三3月調(diào)研考試歷史
- 山東一體化游泳池施工方案
- 塑膠樓地面施工方案
- 橋頭修復(fù)施工方案范本
- 道路鋼筋施工方案
- 森林培育技術(shù)發(fā)展應(yīng)用趨勢(shì)及管理措施的實(shí)踐分析
- 江蘇省泰州市興化市2024-2025學(xué)年九年級(jí)上學(xué)期期末化學(xué)試題(原卷版+解析版)
- 2025年哈爾濱幼兒師范高等??茖W(xué)校單招職業(yè)技能測(cè)試題庫學(xué)生專用
- 第10章 浮力較難2 難題練習(xí) 2021年初中物理培優(yōu)(重點(diǎn)高中自主招生 競(jìng)賽)
- 計(jì)算機(jī)一級(jí)測(cè)試題(附參考答案)
- 企業(yè)內(nèi)部系統(tǒng)使用權(quán)限規(guī)范
- 教學(xué)課件-液壓與氣壓傳動(dòng)項(xiàng)目教程(侯守軍)
- 2024年亳州職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試題庫
- 2025年旅行與旅游的未來:擁抱可持續(xù)與包容性增長(zhǎng)報(bào)告(英文版)-世界經(jīng)濟(jì)論壇
- DB65T 8022-2024 嚴(yán)寒和寒冷地區(qū)居住建筑節(jié)能設(shè)計(jì)標(biāo)準(zhǔn)
- 《質(zhì)子治療技術(shù)》課件
- 醫(yī)院影像科服務(wù)質(zhì)量提升措施
- 2024年中國疾控中心信息中心招聘筆試真題
評(píng)論
0/150
提交評(píng)論