常用算法設(shè)計(jì)方法_第1頁
常用算法設(shè)計(jì)方法_第2頁
常用算法設(shè)計(jì)方法_第3頁
常用算法設(shè)計(jì)方法_第4頁
常用算法設(shè)計(jì)方法_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、常用算法設(shè)計(jì)方法常用算法設(shè)計(jì)方法要使計(jì)算機(jī)能完成人們預(yù)定的工作,首先必須為如何完成預(yù)定的工作設(shè)計(jì)一個(gè)算法,然后再根據(jù)算法編寫程序。計(jì)算機(jī)程序要對(duì)問題的每個(gè)對(duì)象和處理規(guī)則給出正確詳盡的描述,其中程序的數(shù)據(jù)結(jié)構(gòu)和變量用來描述問題的對(duì)象,程序結(jié)構(gòu)、 函數(shù)和語句用來描述問題的算法。算法數(shù)據(jù)結(jié)構(gòu)是程序的兩個(gè)重要方面。算法是問題求解過程的精確描述,一個(gè)算法由有限條可完全機(jī)械地執(zhí)行的、有確定結(jié)果的指令組成。指令正確地描述了要完成的任務(wù)和它們被執(zhí)行的順序。計(jì)算機(jī)按算法指令所描述的順序執(zhí)行算法的指令能在有限的步驟內(nèi)終止,或終止于給出問題的解,或終止于指出問題對(duì)此輸入數(shù)據(jù)無解。通常求解一個(gè)問題可能會(huì)有多種算法可供

2、選擇,選擇的主要標(biāo)準(zhǔn)是算法的正確性和可靠性,簡(jiǎn)單性和易理解性。其次是算法所需要的存儲(chǔ)空間少和執(zhí)行更快等。算法設(shè)計(jì)是一件非常困難的工作,經(jīng)常采用的算法設(shè)計(jì)技術(shù)主要有迭代法、窮舉搜索法、遞推法、貪婪法、回溯法、分治法、動(dòng)態(tài)規(guī)劃法等等。另外,為了更簡(jiǎn)潔的形式設(shè)計(jì)和藐視算法,在算法設(shè)計(jì)時(shí)又常常采用遞歸技術(shù),用遞歸描述算法。一、迭代法迭代法是用于求方程或方程組近似根的一種常用的算法設(shè)計(jì)方法。設(shè)方程為f(x)=0,用某種數(shù)學(xué)方法導(dǎo)出等價(jià)的形式x=g(x) ,然后按以下步驟執(zhí)行:(1)選一個(gè)方程的近似根,賦給變量x0;(2)將 x0 的值保存于變量x1,然后計(jì)算g(x1) ,并將結(jié)果存于變量x0;(3)當(dāng)

3、x0 與 x1 的差的絕對(duì)值還小于指定的精度要求時(shí),重復(fù)步驟(2)的計(jì)算。若方程有根, 并且用上述方法計(jì)算出來的近似根序列收斂,則按上述方法求得的x0 就認(rèn)為是方程的根。上述算法用 C 程序的形式表示為:【算法】迭代法求方程的根x0= 初始近似根;do x1=x0 ;x0=g(x1);/*按特定的方程計(jì)算新的近似根*/ while ( fabs(x0-x1)Epsilon);printf(“方程的近似根是n”, x0) ;迭代算法也常用于求方程組的根,令X=(x0,x1, , xn-1 )設(shè)方程組為:xi=gi(X)(I=0 ,1, , n-1)則求方程組根的迭代算法可描述如下:【算法】迭代法

4、求方程組的根for (i=0;in;i+)xi=初始近似根 ;do for (i=0;in;i+)yi=xi;for (i=0;in;i+)xi=gi(X);for (delta=0.0,i=0;idelta)delta=fabs(yi-xi); while (deltaEpsilon);for (i=0;in;i+)printf(“變量x%d 的近似根是%f”, I , xi);printf(“n”) ;具體使用迭代法求根時(shí)應(yīng)注意以下兩種可能發(fā)生的情況:( 1) 如果方程無解,算法求出的近似根序列就不會(huì)收斂,迭代過程會(huì)變成死循環(huán),因此在使用迭代算法前應(yīng)先考察方程是否有解,并在程序中對(duì)迭代的次

5、數(shù)給予限制;( 2)方程雖然有解,但迭代公式選擇不當(dāng),或迭代的初始近似根選擇不合理,也會(huì)導(dǎo)致迭代失敗。二、窮舉搜索法窮舉搜索法是對(duì)可能是解的眾多候選解按某種順序進(jìn)行逐一枚舉和檢驗(yàn),并從眾找出那些符合要求的候選解作為問題的解?!締栴}】將 A 、B 、C、D 、E、F 這六個(gè)變量排成如圖所示的三角形,這六個(gè)變量分別取1,6上的整數(shù),且均不相同。求使三角形三條邊上的變量之和相等的全部解。如圖就是一個(gè)解。程序引入變量 a、 b、c、 d、e、 f,并讓它們分別順序取 1 至 6 的證書,在它們互不相同的條件下,測(cè)試由它們排成的如圖所示的三角形三條邊上的變量之和是否相等,如相等即為一種滿足要求的排列,把

6、它們輸出。當(dāng)這些變量取盡所有的組合后,程序就可得到全部可能的解。細(xì)節(jié)見下面的程序?!境绦?1】# include void main() int a,b,c,d,e,f; for (a=1;a=6;a+)for (b=1;b=6;b+)if (b=a)continue;for (c=1;c=6;c+)if (c=a)|(c=b)continue;for (d=1;d=6;d+)if (d=a)|(d=b)|(d=c)continue;for (e=1;e=6;e+)if (e=a)|(e=b)|(e=c)|(e=d)continue;f=21-(a+b+c+d+e);if (a+b+c=c+d

7、+e)&(a+b+c=e+f+a)printf(“ %6d,a);printf(“ %4d%4d” ,b,f);printf(“ %2d%4d%4d” ,c,d,e);scanf( “ %*c” );按窮舉法編寫的程序通常不能適應(yīng)變化的情況。如問題改成有9 個(gè)變量排成三角形,每條邊有4 個(gè)變量的情況,程序的循環(huán)重?cái)?shù)就要相應(yīng)改變。對(duì)一組數(shù)窮盡所有排列,還有更直接的方法。將一個(gè)排列看作一個(gè)長(zhǎng)整數(shù),則所有排列對(duì)應(yīng)著一組整數(shù)。將這組整數(shù)按從小到大的順序排列排成一個(gè)整數(shù),從對(duì)應(yīng)最小的整數(shù)開始。按數(shù)列的遞增順序逐一列舉每個(gè)排列對(duì)應(yīng)的每個(gè)整數(shù),這能更有效地完成排列的窮舉。從一個(gè)排列找出對(duì)應(yīng)數(shù)列的下一個(gè)排列可

8、在當(dāng)前排列的基礎(chǔ)上作部分調(diào)整來實(shí)現(xiàn)。倘若當(dāng)前排列為1,2,4,6,5,3,并令其對(duì)應(yīng)的長(zhǎng)整數(shù)為124653。要尋找比長(zhǎng)整數(shù)124653 更大的排列, 可從該排列的最后一個(gè)數(shù)字順序向前逐位考察,當(dāng)發(fā)現(xiàn)排列中的某個(gè)數(shù)字比它前一個(gè)數(shù)字大時(shí),如本例中的6 比它的前一位數(shù)字4 大,這說明還有對(duì)應(yīng)更大整數(shù)的排列。但為了順序從小到大列舉出所有的排列, 不能立即調(diào)整得太大, 如本例中將數(shù)字6 與數(shù)字 4 交換得到的排列 126453就不是排列 124653的下一個(gè)排列。為了得到排列124653 的下一個(gè)排列,應(yīng)從已經(jīng)考察過的那部分?jǐn)?shù)字中選出比數(shù)字大,但又是它們中最小的那一個(gè)數(shù)字,比如數(shù)字5,與數(shù)字4 交換。該

9、數(shù)字也是從后向前考察過程中第一個(gè)比4 大的數(shù)字。 5 與 4 交換后,得到排列125643。在前面數(shù)字 1, 2,5 固定的情況下,還應(yīng)選擇對(duì)應(yīng)最小整數(shù)的那個(gè)排列,為此還需將后面那部分?jǐn)?shù)字的排列順序顛倒,如將數(shù)字6,4, 3 的排列順序顛倒,得到排列1,2,5, 3, 4,6,這才是排列1,2, 4, 6,5,3的下一個(gè)排列。按以上想法編寫的程序如下?!境绦?2】# include # define SIDE_N3# define LENGTH3# define VARIABLES6int A,B,C,D,E,F;int *pt=&A,&B,&C,&D,&E,&F;int *sideSIDE_

10、NLENGTH=&A,&B,&C,&C,&D,&E,&E,&F,&A;int side_totalSIDE_N;main int i,j,t,equal;for (j=0;jV ARIABLES;j+)*ptj=j+1;while(1) for (i=0;iSIDE_N;i+) for (t=j=0;jLENGTH;j+) t+=*sideij;side_totali=t;for (equal=1,i=0;equal&iSIDE_N-1;i+)if (side_totali!=side_totali+1equal=0;if (equal)for (i=1;i0;j-)if (*ptj*ptj-

11、1)break;if (j=0)break;for (i=V ARIABLES-1;i=j;i-)if (*pti*pti-1)break;t=*ptj-1;* ptj-1 =* pti; *pti=t;for (i=V ARIABLES-1;ij;i-,j+)t=*ptj; *ptj =* pti; *pti=t;從上述問題解決的方法中,最重要的因素就是確定某種方法來確定所有的候選解。下面再用一個(gè)示例來加以說明。【問題】背包問題問題描述:有不同價(jià)值、不同重量的物品n 件,求從這n 件物品中選取一部分物品的選擇方案,使選中物品的總重量不超過指定的限制重量,但選中物品的價(jià)值之和最大。設(shè) n 個(gè)物

12、品的重量和價(jià)值分別存儲(chǔ)于數(shù)組w 和 v 中,限制重量為tw??紤]一個(gè)n 元組( x0, x1,xn-1),其中xi=0表示第i 個(gè)物品沒有選取,而xi=1 則表示第i 個(gè)物品被選取。顯然這個(gè)n 元組等價(jià)于一個(gè)選擇方案。用枚舉法解決背包問題,需要枚舉所有的選取方案,而根據(jù)上述方法,我們只要枚舉所有的n 元組,就可以得到問題的解。顯然,每個(gè)分量取值為0 或 1 的 n 元組的個(gè)數(shù)共為2n 個(gè)。而每個(gè) n 元組其實(shí)對(duì)應(yīng)了一個(gè)長(zhǎng)度為n 的二進(jìn)制數(shù),且這些二進(jìn)制數(shù)的取值范圍為 0 2n-1。因此,如果把 0 2n-1 分別轉(zhuǎn)化為相應(yīng)的二進(jìn)制數(shù),則可以得到我們所需要的 2n 個(gè) n 元組?!舅惴ā縨axv

13、=0;for (i=0;i2n;i+) B0.n-1=0;把 i 轉(zhuǎn)化為二進(jìn)制數(shù),存儲(chǔ)于數(shù)組B 中 ;temp_w=0;temp_v=0;for (j=0;jn;j+) if (Bj=1) temp_w=temp_w+wj;temp_v=temp_v+vj;if (temp_wmaxv) maxv=temp_v;保存該 B 數(shù)組;三、遞推法遞推法是利用問題本身所具有的一種遞推關(guān)系求問題解的一種方法。設(shè)要求問題規(guī)模為N 的解,當(dāng) N=1時(shí),解或?yàn)橐阎蚰芊浅7奖愕氐玫浇?。能采用遞推法構(gòu)造算法的問題有重要的遞推性質(zhì),即當(dāng)?shù)玫絾栴}規(guī)模為 i-1 的解后,由問題的遞推性質(zhì),能從已求得的規(guī)模為1, 2

14、, , i-1 的一系列解,構(gòu)造出問題規(guī)模為 I 的解。這樣,程序可從i=0 或 i=1 出發(fā),重復(fù)地,由已知至i-1 規(guī)模的解,通過遞推,獲得規(guī)模為i的解,直至得到規(guī)模為 N 的解?!締栴}】階乘計(jì)算問題描述:編寫程序,對(duì)給定的n(n 100),計(jì)算并輸出 k 的階乘 k ?。?k=1 ,2, ,n)的全部有效數(shù)字。由于要求的整數(shù)可能大大超出一般整數(shù)的位數(shù),程序用一維數(shù)組存儲(chǔ)長(zhǎng)整數(shù),存儲(chǔ)長(zhǎng)整數(shù)數(shù)組的每個(gè)元素只存儲(chǔ)長(zhǎng)整數(shù)的一位數(shù)字。如有m 位成整數(shù) N 用數(shù)組 a 存儲(chǔ):N=am 10m-1+am-1 10m-2+a2 101+a1 100并用 a0 存儲(chǔ)長(zhǎng)整數(shù) N 的位數(shù) m,即 a0=m 。

15、按上述約定,數(shù)組的每個(gè)元素存儲(chǔ)k 的階乘 k!的一位數(shù)字,并從低位到高位依次存于數(shù)組的第二個(gè)元素、第三個(gè)元素。例如, 5!=120,在數(shù)組中的存儲(chǔ)形式為:3 0 21首元素 3 表示長(zhǎng)整數(shù)是一個(gè) 3 位數(shù),接著是低位到高位依次是0、 2、1,表示成整數(shù) 120。計(jì)算階乘 k!可采用對(duì)已求得的階乘 (k-1) !連續(xù)累加 k-1次后求得。例如,已知4! =24,計(jì)算 5!,可對(duì)原來的 24累加 4 次 24 后得到 120 。細(xì)節(jié)見以下程序。# include # include # define MAXN 1000 void pnext(int a ,int k) int *b,m=a0,i,

16、j,r,carry;b=(int * ) malloc(sizeof(int)* (m+1);for ( i=1;i=m;i+)bi=ai;for ( j=1;j=k;j+) for ( carry=0,i=1;i=m;i+) r=(i0;i-)prin tf(“ %d” ,ai);printf(“n” );void main() int aMAXN,n,k;printf(“ Enter the number“n:);scanf( “ %d” ,&n);a0=1;a1=1;write(a,1);for (k=2;k1 時(shí))。寫成遞歸函數(shù)有:int fib(int n)if (n=0)if (n

17、=1)if (n1)return 0;return 1;return fib(n-1)+fib(n-2);遞歸算法的執(zhí)行過程分遞推和回歸兩個(gè)階段。在遞推階段,把較復(fù)雜的問題(規(guī)模為n)的求解推到比原問題簡(jiǎn)單一些的問題(規(guī)模小于n)的求解。例如上例中,求解fib(n) ,把它推到求解fib(n-1) 和 fib(n-2) 。也就是說,為計(jì)算fib(n) ,必須先計(jì)算fib(n-1) 和 fib(n-2) ,而計(jì)算fib(n-1) 和fib(n-2) ,又必須先計(jì)算fib(n-3)和 fib(n-4)。依次類推,直至計(jì)算fib(1) 和 fib(0) ,分別能立即得到結(jié)果1 和 0。在遞推階段,必

18、須要有終止遞歸的情況。例如在函數(shù)fib中,當(dāng)n 為 1 和 0 的情況。在回歸階段,當(dāng)獲得最簡(jiǎn)單情況的解后,逐級(jí)返回,依次得到稍復(fù)雜問題的解,例如得到fib(1) 和fib(0)后,返回得到fib(2) 的結(jié)果,在得到了fib(n-1) 和 fib(n-2) 的結(jié)果后,返回得到fib(n) 的結(jié)果。在編寫遞歸函數(shù)時(shí)要注意,函數(shù)中的局部變量和參數(shù)知識(shí)局限于當(dāng)前調(diào)用層,當(dāng)遞推進(jìn)入“簡(jiǎn)單問題 ”層時(shí),原來層次上的參數(shù)和局部變量便被隱蔽起來。在一系列“簡(jiǎn)單問題 ”層,它們各有自己的參數(shù)和局部變量。由于遞歸引起一系列的函數(shù)調(diào)用,并且可能會(huì)有一系列的重復(fù)計(jì)算,遞歸算法的執(zhí)行效率相對(duì)較低。當(dāng)某個(gè)遞歸算法能較

19、方便地轉(zhuǎn)換成遞推算法時(shí),通常按遞推算法編寫程序。例如上例計(jì)算斐波那契數(shù)列的第n 項(xiàng)的函數(shù) fib(n) 應(yīng)采用遞推算法,即從斐波那契數(shù)列的前兩項(xiàng)出發(fā),逐次由前兩項(xiàng)計(jì)算出下一項(xiàng),直至計(jì)算出要求的第 n 項(xiàng)?!締栴}】組合問題問題描述:找出從自然數(shù)1、2、n 中任取 r 個(gè)數(shù)的所有組合。例如n=5,r=3 的所有組合為:(1)5、 4、3(2) 5、4、2(3) 5、4、1( 4)5、3、2( 5)5、3、 1( 6)5、2、 1( 7)4、3、2( 8)4、3、 1( 9)4、2、 1( 10) 3、2、1分析所列的10 個(gè)組合,可以采用這樣的遞歸思想來考慮求組合函數(shù)的算法。設(shè)函數(shù)為void co

20、mb(int m,intk)為找出從自然數(shù)1、 2、 m 中任取 k 個(gè)數(shù)的所有組合。當(dāng)組合的第一個(gè)數(shù)字選定時(shí),其后的數(shù)字是從余下的 m-1 個(gè)數(shù)中取k-1 數(shù)的組合。這就將求m 個(gè)數(shù)中取k 個(gè)數(shù)的組合問題轉(zhuǎn)化成求m-1 個(gè)數(shù)中取k-1個(gè)數(shù)的組合問題。 設(shè)函數(shù)引入工作數(shù)組a 存放求出的組合的數(shù)字,約定函數(shù)將確定的k 個(gè)數(shù)字組合的第一個(gè)數(shù)字放在ak 中,當(dāng)一個(gè)組合求出后,才將a 中的一個(gè)組合輸出。第一個(gè)數(shù)可以是m、 m-1 、 k,函數(shù)將確定組合的第一個(gè)數(shù)字放入數(shù)組后,有兩種可能的選擇,因還未去頂組合的其余元素,繼續(xù)遞歸去確定;或因已確定了組合的全部元素,輸出這個(gè)組合。細(xì)節(jié)見以下程序中的函數(shù)co

21、mb。【程序】# include # define MAXN 100 int aMAXN;voidcomb(int m,int k) int i,j;for (i=m;i=k;i-) ak=i; if (k1)comb(i-1,k-1);else for (j=a0;j0;j-)printf(“ %4d” ,aj);printf(n“” );void main() a0=3;comb(5,3);【問題】背包問題問題描述:有不同價(jià)值、不同重量的物品n 件,求從這n 件物品中選取一部分物品的選擇方案,使選中物品的總重量不超過指定的限制重量,但選中物品的價(jià)值之和最大。設(shè) n 件物品的重量分別為w0、

22、 w1、 wn-1,物品的價(jià)值分別為v0、v1、vn-1 。采用遞歸尋找物品的選擇方案。設(shè)前面已有了多種選擇的方案,并保留了其中總價(jià)值最大的方案于數(shù)組option ,該方案的總價(jià)值存于變量maxv 。當(dāng)前正在考察新方案,其物品選擇情況保存于數(shù)組cop 。假定當(dāng)前方案已考慮了前 i-1 件物品, 現(xiàn)在要考慮第 i 件物品; 當(dāng)前方案已包含的物品的重量之和為 tw;至此,若其余物品都選擇是可能的話,本方案能達(dá)到的總價(jià)值的期望值為 tv 。算法引入 tv 是當(dāng)一旦當(dāng)前方案的總價(jià)值的期望值也小于前面方案的總價(jià)值 maxv 時(shí),繼續(xù)考察當(dāng)前方案變成無意義的工作,應(yīng)終止當(dāng)前方案,立即去考察下一個(gè)方案。因?yàn)?/p>

23、當(dāng)方案的總價(jià)值不比 maxv 大時(shí),該方案不會(huì)被再考察,這同時(shí)保證函數(shù)后找到的方案一定會(huì)比前面的方案更好。對(duì)于第 i 件物品的選擇考慮有兩種可能:( 1) 考慮物品 i 被選擇,這種可能性僅當(dāng)包含它不會(huì)超過方案總重量限制時(shí)才是可行的。選中后,繼續(xù)遞歸去考慮其余物品的選擇。(2)考慮物品 i 不被選擇,這種可能性僅當(dāng)不包含物品i 也有可能會(huì)找到價(jià)值更大的方案的情況。按以上思想寫出遞歸算法如下:try( 物品 i,當(dāng)前選擇已達(dá)到的重量和,本方案可能達(dá)到的總價(jià)值tv)/* 考慮物品 i 包含在當(dāng)前方案中的可能性*/if( 包含物品i 是可以接受的)將物品i 包含在當(dāng)前方案中;if (in-1)try

24、(i+1,tw+物品i的重量 ,tv);else/* 又一個(gè)完整方案,因?yàn)樗惹懊娴姆桨负?,以它作為最佳方?/以當(dāng)前方案作為臨時(shí)最佳方案保存;恢復(fù)物品 i 不包含狀態(tài);/* 考慮物品 i 不包含在當(dāng)前方案中的可能性*/if ( 不包含物品i 僅是可男考慮的)if (in-1)try(i+1,tw,tv- 物品 i 的價(jià)值 );else/* 又一個(gè)完整方案,因它比前面的方案好,以它作為最佳方案*/以當(dāng)前方案作為臨時(shí)最佳方案保存;為了理解上述算法,特舉以下實(shí)例。設(shè)有4 件物品,它們的重量和價(jià)值見表:物品0123重量5321價(jià)值4431并設(shè)限制重量為 7。則按以上算法,下圖表示找解過程。由圖知,一

25、旦找到一個(gè)解,算法就進(jìn)一步找更好的佳。如能判定某個(gè)查找分支不會(huì)找到更好的解,算法不會(huì)在該分支繼續(xù)查找,而是立即終止該分支,并去考察下一個(gè)分支。按上述算法編寫函數(shù)和程序如下:【程序】# include # define N 100doublelimitW,totV ,maxV;intoptionN,copN;structdoubleweight;doublevalue;aN;intn;void find(int i,double tw,double tv) int k;/* 考慮物品i 包含在當(dāng)前方案中的可能性*/if (tw+ai.weight=limitW) copi=1;if (in-1)

26、find(i+1,tw+ai.weight,tv);else for (k=0;kmaxV)if (in-1)find(i+1,tw,tv-ai.value);else for (k=0;kn;k+) optionk=copk;maxv=tv-ai.value;void main() int k; double w,v;printf( 輸“入物品種數(shù) n” );scanf(“ %d” ,&n);printf(輸“入各物品的重量和價(jià)值n” );for (totv=0.0,k=0;kn;k+) scanf( “ %1f%1f” ,&w,&v); ak.weight=w;ak.value=v;tot

27、V+=V;printf(輸“入限制重量n” );scanf( “ %1f” ,&limitV);maxv=0.0;for (k=0;kn;k+)copk=0;find(0,0.0,totV);for (k=0;kn;k+)if (optionk)printf(“ %4d” ,k+1);printf(n“總價(jià)值為n” ,maxv);作為對(duì)比,下面以同樣的解題思想,考慮非遞歸的程序解。為了提高找解速度,程序不是簡(jiǎn)單地逐一生成所有候選解,而是從每個(gè)物品對(duì)候選解的影響來形成值得進(jìn)一步考慮的候選解,一個(gè)候選解是通過依次考察每個(gè)物品形成的。對(duì)物品i 的考察有這樣幾種情況:當(dāng)該物品被包含在候選解中依舊滿足解

28、的總重量的限制,該物品被包含在候選解中是應(yīng)該繼續(xù)考慮的;反之,該物品不應(yīng)該包括在當(dāng)前正在形成的候選解中。同樣地,僅當(dāng)物品不被包括在候選解中,還是有可能找到比目前臨時(shí)最佳解更好的候選解時(shí),才去考慮該物品不被包括在候選解中;反之,該物品不包括在當(dāng)前候選解中的方案也不應(yīng)繼續(xù)考慮。對(duì)于任一值得繼續(xù)考慮的方案,程序就去進(jìn)一步考慮下一個(gè)物品?!境绦颉? include # define N 100 double limitW; int copN;struct ele double weight;doublevalue; aN;intk,n;structintflg;doubletw;doubletv;tw

29、vN;void next(int i,double tw,double tv) twvi.flg=1;twvi.tw=tw;twvi.tv=tv;double find(struct ele *a,int n) int i,k,f;double maxv,tw,tv,totv;maxv=0;for (totv=0.0,k=0;kn;k+)totv+=ak.value;next(0,0.0,totv);i=0; f=twvi.flg; tw=twvi.tw; tv=twvi.tv;switch(f) case 1: twvi.flg+;if (tw+ai.weight=limitW)if (in

30、-1) next(i+1,tw+ai.weight,tv); i+;else maxv=tv;for (k=0;kmaxv)if (in-1) next(i+1,tw,tv-ai.value);i+;else maxv=tv-ai.value;for (k=0;kn;k+) copk=twvk.flg!=0;break;return maxv;void main() double maxv;printf(輸“入物品種數(shù)n” );scanf(“ %d” ,&n);printf(輸“入限制重量n” );scanf( “ %1f” ,&limitW);printf( 輸“入各物品的重量和價(jià)值n” )

31、;for (k=0;kn;k+)scanf( “ %1f%1f” ,&ak.weight,&ak.value);maxv=find(a,n);printf(n“選中的物品為n” );for (k=0;kn;k+)if (optionk)printf(“ %4d” ,k+1);printf(n“總價(jià)值為n” ,maxv);五、回溯法回溯法也稱為試探法, 該方法首先暫時(shí)放棄關(guān)于問題規(guī)模大小的限制, 并將問題的候選解按某種順序逐一枚舉和檢驗(yàn)。當(dāng)發(fā)現(xiàn)當(dāng)前候選解不可能是解時(shí),就選擇下一個(gè)候選解;倘若當(dāng)前候選解除了還不滿足問題規(guī)模要求外,滿足所有其他要求時(shí),繼續(xù)擴(kuò)大當(dāng)前候選解的規(guī)模,并繼續(xù)試探。如果當(dāng)前候

32、選解滿足包括問題規(guī)模在內(nèi)的所有要求時(shí),該候選解就是問題的一個(gè)解。在回溯法中,放棄當(dāng)前候選解,尋找下一個(gè)候選解的過程稱為回溯。擴(kuò)大當(dāng)前候選解的規(guī)模,以繼續(xù)試探的過程稱為向前試探。1、回溯法的一般描述可用回溯法求解的問題P,通常要能表達(dá)為:對(duì)于已知的由n 元組( x1,x2 , , xn)組成的一個(gè)狀態(tài)空間 E= (x1,x2, , xn)xi Si , i=1 ,2, , n ,給定關(guān)于n 元組中的一個(gè)分量的一個(gè)約束集D,要求 E 中滿足 D 的全部約束條件的所有n 元組。其中Si 是分量 xi 的定義域,且|Si|有限, i=1 ,2, ,n。我們稱E 中滿足 D 的全部約束條件的任一n 元組

33、為問題P 的一個(gè)解。解問題 P 的最樸素的方法就是枚舉法,即對(duì)E 中的所有 n 元組逐一地檢測(cè)其是否滿足D 的全部約束,若滿足,則為問題P 的一個(gè)解。但顯然,其計(jì)算量是相當(dāng)大的。我們發(fā)現(xiàn),對(duì)于許多問題,所給定的約束集D 具有完備性,即i 元組( x1,x2, , xi )滿足 D 中僅涉及到 x1 ,x2, ,xi 的所有約束意味著 j(jj 。因此,對(duì)于約束集 D 具有完備性的問題 P,一旦檢測(cè)斷定某個(gè) j 元組( x1,x2, , xj )違反 D 中僅涉及 x1,x2, , xj 的一個(gè)約束,就可以肯定,以( x1,x2, , xj )為前綴的任何 n 元組( x1,x2, , xj ,

34、xj+1 , , xn)都不會(huì)是問題 P 的解,因而就不必去搜索它們、檢測(cè)它們?;厮莘ㄕ轻槍?duì)這類問題,利用這類問題的上述性質(zhì)而提出來的比枚舉法效率更高的算法?;厮莘ㄊ紫葘栴} P 的 n 元組的狀態(tài)空間E 表示成一棵高為 n 的帶權(quán)有序樹 T,把在 E 中求問題 P 的所有解轉(zhuǎn)化為在 T 中搜索問題 P 的所有解。樹T 類似于檢索樹,它可以這樣構(gòu)造:設(shè) Si 中的元素可排成 xi(1),xi(2), , xi(mi-1),|Si| =mi , i=1 ,2, , n。從根開始,讓T的第 I層的每一個(gè)結(jié)點(diǎn)都有 mi 個(gè)兒子。這 mi 個(gè)兒子到它們的雙親的邊,按從左到右的次序,分別帶權(quán)xi+1(

35、1),xi+1(2) , , xi+1(mi),i=0 , 1,2, , n-1 。照這種構(gòu)造方式,E 中的一個(gè) n 元組( x1,x2, , xn)對(duì)應(yīng)于 T 中的一個(gè)葉子結(jié)點(diǎn),T 的根到這個(gè)葉子結(jié)點(diǎn)的路徑上依次的n 條邊的權(quán)分別為x1,x2, , xn,反之亦然。另外,對(duì)于任意的0i n-1 ,E 中 n 元組( x1,x2, , xn)的一個(gè)前綴 I元組(x1,x2, , xi )對(duì)應(yīng)于 T 中的一個(gè)非葉子結(jié)點(diǎn),T 的根到這個(gè)非葉子結(jié)點(diǎn)的路徑上依次的I條邊的權(quán)分別為 x1,x2, , xi ,反之亦然。特別, E 中的任意一個(gè) n 元組的空前綴(),對(duì)應(yīng)于T 的根。因而,在 E 中尋找問

36、題 P 的一個(gè)解等價(jià)于在 T 中搜索一個(gè)葉子結(jié)點(diǎn), 要求從 T 的根到該葉子結(jié)點(diǎn)的路徑上依次的 n 條邊相應(yīng)帶的 n 個(gè)權(quán) x1,x2, , xn 滿足約束集 D 的全部約束。在T 中搜索所要求的葉子結(jié)點(diǎn),很自然的一種方式是從根出發(fā),按深度優(yōu)先的策略逐步深入,即依次搜索滿足約束條件的前綴1 元組(x1i )、前綴 2 元組( x1,x2)、 ,前綴 I 元組( x1,x2, , xi ), ,直到 i=n 為止。在回溯法中, 上述引入的樹被稱為問題P 的狀態(tài)空間樹; 樹 T 上任意一個(gè)結(jié)點(diǎn)被稱為問題P 的狀態(tài)結(jié)點(diǎn);樹 T 上的任意一個(gè)葉子結(jié)點(diǎn)被稱為問題P 的一個(gè)解狀態(tài)結(jié)點(diǎn);樹 T 上滿足約束集

37、 D 的全部約束的任意一個(gè)葉子結(jié)點(diǎn)被稱為問題P 的一個(gè)回答狀態(tài)結(jié)點(diǎn),它對(duì)應(yīng)于問題P 的一個(gè)解?!締栴}】組合問題問題描述:找出從自然數(shù)1、 2、 、 n 中任取 r個(gè)數(shù)的所有組合。例如 n=5, r=3 的所有組合為:(1)1、 2、3( 2)1、2、 4(3) 1、 2、 5( 4)1、3、4(5) 1、 3、5( 6)1、4、 5( 7)2、3、4(8) 2、 3、5( 9)2、4、 5( 10) 3、4、5則該問題的狀態(tài)空間為:E= (x1,x2,x3)xi S ,i=1 , 2,3 其中: S=1, 2,3, 4, 5約束集為:x1x2ai ,后一個(gè)數(shù)字比前一個(gè)大;( 2) ai-i=n

38、-r+1 。按回溯法的思想,找解過程可以敘述如下:首先放棄組合數(shù)個(gè)數(shù)為r 的條件,候選組合從只有一個(gè)數(shù)字1 開始。因該候選解滿足除問題規(guī)模之外的全部條件,擴(kuò)大其規(guī)模,并使其滿足上述條件(1),候選組合改為1,2。繼續(xù)這一過程,得到候選組合1,2, 3。該候選解滿足包括問題規(guī)模在內(nèi)的全部條件,因而是一個(gè)解。在該解的基礎(chǔ)上,選下一個(gè)候選解,因 a2 上的3 調(diào)整為4,以及以后調(diào)整為5 都滿足問題的全部要求,得到解1,2,4 和 1, 2, 5。由于對(duì)5不能再作調(diào)整,就要從a2 回溯到 a1 ,這時(shí), a1=2 ,可以調(diào)整為3,并向前試探,得到解1, 3, 4。重復(fù)上述向前試探和向后回溯,直至要從a0 再回溯時(shí),說明已經(jīng)找完問題的全部解。按上述思想寫成程序如下:【程序】# define MAXN 100 int aMAXN;void comb(int m,int r) int i,j;i=0;ai=1; do if (ai-i=m-r+1 if (i=r-1) for (j=0;jr;j+)printf(“ %4d” ,aj);printf(n“” );ai+;continue;else if (i=0) return;a-i+; while (1)main() comb(5,3);【問題】填字游戲問題描述:在 33 個(gè)方格的方陣中要填入數(shù)字 1 到 N(N10)內(nèi)的某 9

溫馨提示

  • 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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論