演算法活結點
『壹』 闃愯堪鍥炴函綆楁硶鍜屽垎鏋濋檺鐣岀畻娉曠殑鍏卞悓鐐瑰拰涓嶅悓鐐,鎻愰珮綆楁硶鏁堢巼鐨勫叧閿鏄浠涔堬紵
鍥炴函綆楁硶鍜屽垎鏀闄愮晫綆楁硶閮芥槸鍦ㄩ棶棰樼殑瑙g┖闂翠笂鎼滅儲闂棰樿В鐨勭畻娉曪紝瀹冧滑鏈変竴浜涚浉鍚岀偣鍜屼笉鍚岀偣錛
鐩稿悓鐐癸細
閮芥槸涓縐嶆棦甯︽湁緋葷粺鎬у張甯︽湁璺寵穬鎬х殑鎼滅儲綆楁硶銆
閮芥槸鍩轟簬絀蜂婦鎼滅儲鐨勭畻娉曪紝閮介渶瑕佽懼畾涓涓鍒濆嬭В錛岀劧鍚庨氳繃涓嶆柇鍦版灇涓炬悳緔㈡潵閫愭ユ帴榪戞渶浼樿В銆
閮藉彲浠ュ簲鐢ㄤ簬闈炵嚎鎬ц勫垝闂棰樼殑奼傝В銆
奼傝В鐩鏍囦笉鍚岋細鍥炴函娉曠殑奼傝В鐩鏍囨槸鎵懼嚭鎵鏈夋弧瓚崇害鏉熸潯浠剁殑瑙o紝鑰屽垎鏀闄愮晫娉曠殑奼傝В鐩鏍囧垯鏄鎵懼嚭浣跨洰鏍囧嚱鏁板艱揪鍒版瀬澶ф垨鏋佸皬鐨勮В錛屾垨鏄鍦ㄦ弧瓚崇害鏉熸潯浠剁殑瑙d腑鎵懼嚭鏈浼樿В銆
鎼滅儲鏂瑰紡涓嶅悓錛氬洖婧娉曢氬父閲囩敤灝濊瘯浼樺厛鎼滅儲錛岃屽垎鏀闄愮晫娉曞垯閫氬父閲囩敤騫垮害浼樺厛鎼滅儲銆
瀵硅妭鐐瑰瓨鍌ㄧ殑瑕佹眰涓嶅悓錛氬垎鏀闄愮晫娉曢氬父闇瑕佸瓨鍌ㄤ竴浜涢濆栫殑淇℃伅浠ュ埄浜庤繘涓姝ュ湴灞曞紑鎼滅儲錛岃屽洖婧娉曞垯涓嶉渶瑕併
瀛樺偍絀洪棿鐨勮佹眰涓嶅悓錛氬垎鏀闄愮晫娉曠殑綆楁硶妗嗘灦涓錛屾瘡涓涓媧葷粨鐐瑰彧鏈変竴嬈℃満浼氭垚涓烘墿灞曠粨鐐癸紝鑰屽洖婧娉曞垯娌℃湁榪欐牱鐨勯檺鍒躲
涓嶅悓鐐癸細
鎻愰珮綆楁硶鏁堢巼鐨勫叧閿鏄鍒嗘敮闄愮晫綆楁硶銆備笌鍥炴函綆楁硶鐩告瘮錛屽垎鏀闄愮晫綆楁硶閲囩敤浜嗕竴嬈℃т駭鐢熸墍鏈夊効瀛愮粨鐐圭殑鏂瑰紡錛岄伩鍏嶄簡鍥炴函綆楁硶涓闇瑕佷笉鏂榪涜岀姸鎬佽漿縐誨拰鍥炴函鐨勮繃紼嬶紝浠庤屾彁楂樹簡綆楁硶鏁堢巼銆傛ゅ栵紝鍒嗘敮闄愮晫綆楁硶榪樺彲浠ラ氳繃浣跨敤闃熷垪寮忔垨浼樺厛闃熷垪寮忕殑瀛樺偍鏂瑰紡錛屾潵閬垮厤鍥炴函綆楁硶涓闇瑕佽繘琛岀殑棰濆栫姸鎬佽漿縐繪搷浣滐紝榪涗竴姝ユ彁楂樼畻娉曟晥鐜囥
『貳』 回溯法的基本思想是什麼
回溯法又稱試探法。回溯法的基本做法是深度優先搜索,是一種組織得井井有條的、能避免不必要重復搜索的窮舉式搜索演算法。
回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。
當我們遇到某一類問題時,它的問題可以分解,但是又不能得出明確的動態規劃或是遞歸解法,此時可以考慮用回溯法解決此類問題。回溯法的優點在於其程序結構明確,可讀性強,易於理解,而且通過對問題的分析可以大大提高運行效率。但是,對於可以得出明顯的遞推公式迭代求解的問題,還是不要用回溯法,因為它花宏歷滑費的時間比較長。
對於用回溯法求解的問題,首先要將問題進行適當的轉化,得出狀態空間樹。這棵樹的每條完整路徑都代表了一種解的可能。通過深度優先搜索這棵樹,枚舉每種可能的解的情況;從而得出結果。但是,回溯法中通過構造約束函數,可以大大提升程序效率,因為在深度優先搜索的過程中,不斷的將每個解(並不一定是完整的,事實上這也就是構造約束函數的意義所在)與約束函數進行對照從而刪除一些不可能的解,這樣就不必繼續把解的剩餘部分列出從而節省部分時間。
回溯法中,首先需要明確下面三個概念:
(一)約束函數:約束函數是根據題意定出的。通過描述合法解的一般特徵用於去除不合法的解,從而避免繼續搜索出這個不合法解的剩餘部分。因此,約束函數是對於任何狀態空間樹上的節點都有效、等價的。
(二)狀態空間樹:剛剛已經提到,狀態空間樹是一個對所有解的圖形描述。樹上的每個子節點的解都只有一個部分與父節點不同。
(三)擴展節點、活結點、死結點:所謂擴展節點,就是當前正在求出它的子節點的節點,在深度優先搜索中,爛亂只允許有一個擴展節點。活結點就是通過與約束函數的對照,節點本身和其父節點均滿足約束函數要求的節點;死結點反之。由此很容易知道死結點是不必求出其子節點的(沒有意義)。
利用回溯法解題的具體步驟
首先,要通過讀題完成下面三個步驟:
(1)描述解的形式,定義一個解空間,它包含問題的所有解。
(2)構造狀態空間樹。
(3)構造約束函數(用於殺死節點)。
然後就要通蔽臘過深度優先搜索思想完成回溯,完整過程如下:
(1)設置初始化的方案(給變數賦初值,讀入已知數據等)。
(2)變換方式去試探,若全部試完則轉(7)。
(3)判斷此法是否成功(通過約束函數),不成功則轉(2)。
(4)試探成功則前進一步再試探。
(5)正確方案還未找到則轉(2)。
(6)已找到一種方案則記錄並列印。
(7)退回一步(回溯),若未退到頭則轉(2)。
(8)已退到頭則結束或列印無解
『叄』 五大基本演算法——回溯法
回溯法是一種選優搜索法(試探法)。
基本思想:將問題P的狀態空間E表示成一棵高為n的帶全有序樹T,把求解問題簡化為搜索樹T。搜索過程採用 深度優先搜索 。搜索到某一結點時判斷該結點是否包含原問題的解,如果包含則繼續往下搜索,如果不包含則向祖先回溯。
通俗來說,就是利用一個樹結構來表示解空間,然後從樹的根開始深度優先遍歷該樹,到不滿足要求的葉子結點時向上回溯繼續遍歷。
幾個結點:
擴展結點:一個正在產生子結點的結點稱為擴展結點
活結點:一個自身已生成但未全部生成子結點的結點
死結點:一個所有子結點已全部生成的結點
1、分析問題,定義問題解空間。
2、根據解空間,確定解空間結構,得 搜索樹 。
3、從根節點開始深度優先搜索解空間(利用 剪枝 避免無效搜索)。
4、遞歸搜索,直到找到所要求的的解。
1、子集樹
當問題是:從n個元素的集合S中找出滿足某種性質的子集時,用子集樹。
子集樹必然是一個二叉樹。常見問題:0/1背包問題、裝載問題。
遍歷子集樹時間復雜度:O(2^n)
2、排列樹
當問題是:確定n個元素滿足某種排列時,用排列數。常見問題:TSP旅行商問題,N皇後問題。
遍歷排列樹時間復雜度:O(n!)
通俗地講,結合Java集合的概念,選擇哪種樹其實就是看最後所得結果是放入一個List(有序)里,還是放入一個Set(無序)里。
剪枝函數能極大提高搜索效率,遍歷解空間樹時,對於不滿足條件的分支進行剪枝,因為這些分支一定不會在最後所求解中。
常見剪枝函數:
約束函數(對解加入約束條件)、限界函數(對解進行上界或下界的限定)
滿足約束函數的解才是可行解。
1、0/1背包問題
2、TSP旅行商問題
3、最優裝載問題
4、N-皇後問題
具體問題可網路詳細內容。
『肆』 什麼是分支演算法
分支限界演算法:
分支定界 (branch and bound) 演算法是一種在問題的解空間樹上搜索問題的解的方法。但與回溯演算法不同,分支定界演算法採用廣度優先或最小耗費優先的方法搜索解空間樹,並且,在分支定界演算法中,每一個活結點只有一次機會成為擴展結點。
利用分支定界演算法對問題的解空間樹進行搜索,它的搜索策略是:
1 .產生當前擴展結點的所有孩子結點;
2 .在產生的孩子結點中,拋棄那些不可能產生可行解(或最優解)的結點;
3 .將其餘的孩子結點加入活結點表;
4 .從活結點表中選擇下一個活結點作為新的擴展結點。
如此循環,直到找到問題的可行解(最優解)或活結點表為空。
從活結點表中選擇下一個活結點作為新的擴展結點,根據選擇方式的不同,分支定界演算法通常可以分為兩種形式:
1 . FIFO(First In First Out) 分支定界演算法:按照先進先出原則選擇下一個活結點作為擴展結點,即從活結點表中取出結點的順序與加入結點的順序相同。
2 .最小耗費或最大收益分支定界演算法:在這種情況下,每個結點都有一個耗費或收益。如果要查找一個具有最小耗費的解,那麼要選擇的下一個擴展結點就是活結點表中具有最小耗費的活結點;如果要查找一個具有最大收益的解,那麼要選擇的下一個擴展結點就是活結點表中具有最大收益的活結點。
又稱分支定界搜索法。過程系統綜合的一類方法。該法是將原始問題分解,產生一組子問題。分支是將一組解分為幾組子解,定界是建立這些子組解的目標函數的邊界。如果某一子組的解在這些邊界之外,就將這一子組舍棄(剪枝)。分支定界法原為運籌學中求解整數規劃(或混合整數規劃)問題的一種方法。用該法尋求整數最優解的效率很高。將該法原理用於過程系統綜合可大大減少需要計算的方案數日。
分支定界法的思想是:首先確定目標值的上下界,邊搜索邊減掉搜索樹的某些支,提高搜索效率。
在競賽中,我們有時會碰到一些題目,它們既不能通過建立數學模型解決,又沒有現成演算法可以套用,或者非遍歷所有狀況才可以得出正確結果。這時,我們就必須採用搜索演算法來解決問題。
搜索演算法按搜索的方式分有兩類,一類是深度優先搜索,一類是廣度優先搜索。我們知道,深度搜索編程簡單,程序簡潔易懂,空間需求也比較低,但是這種方法的時間復雜度往往是指數級的,倘若不加優化,其時間效率簡直無法忍受;而廣度優先搜索雖然時間復雜度比前者低一些,但其龐大的空間需求量又往往讓人望而卻步。
所以,對程序進行優化,就成為搜索演算法編程中最關鍵的一環。
本文所要討論的便是搜索演算法中優化程序的一種基本方法棗「剪枝」。
什麼是剪枝
相信剛開始接觸搜索演算法的人,都做過類似迷宮這樣的題目吧。我們在「走迷宮」的時候,一般回溯法思路是這樣的:
1、這個方向有路可走,我沒走過
2、往這個方向前進
3、是死胡同,往回走,回到上一個路口
4、重復第一步,直到找著出口
這樣的思路很好理解,編程起來也比較容易。但是當迷宮的規模很大時,回溯法的缺點便暴露無遺:搜索耗時極巨,無法忍受。
我們可不可以在向某個方向前進時,先一步判斷出這樣走會不會走到死胡同里呢?這樣一來,搜索的時間不就可以減少了嗎?
答案是:可以的。
剪枝的概念,其實就跟走迷宮避開死胡同差不多。若我們把搜索的過程看成是對一棵樹的遍歷,那麼剪枝顧名思義,就是將樹中的一些「死胡同」,不能到達我們需要的解的枝條「剪」掉,以減少搜索的時間。
搜索演算法,絕大部分需要用到剪枝。然而,不是所有的枝條都可以剪掉,這就需要通過設計出合理的判斷方法,以決定某一分支的取捨。在設計判斷方法的時候,需要遵循一定的原則。
剪枝的原則
1、正確性
正如上文所述,枝條不是愛剪就能剪的。如果隨便剪枝,把帶有最優解的那一分支也剪掉了的話,剪枝也就失去了意義。所以,剪枝的前提是一定要保證不丟失正確的結果。
2、准確性
在保證了正確性的基礎上,我們應該根據具體問題具體分析,採用合適的判斷手段,使不包含最優解的枝條盡可能多的被剪去,以達到程序「最優化」的目的。可以說,剪枝的准確性,是衡量一個優化演算法好壞的標准。
3、高效性 設計優化程序的根本目的,是要減少搜索的次數,使程序運行的時間減少。但為了使搜索次數盡可能的減少,我們又必須花工夫設計出一個准確性較高的優化演算法,而當演算法的准確性升高,其判斷的次數必定增多,從而又導致耗時的增多,這便引出了矛盾。
因此,如何在優化與效率之間尋找一個平衡點,使得程序的時間復雜度盡可能降低,同樣是非常重要的。倘若一個剪枝的判斷效果非常好,但是它卻需要耗費大量的時間來判斷、比較,結果整個程序運行起來也跟沒有優化過的沒什麼區別,這樣就太得不償失了。
綜上所述,我們可以把剪枝優化的主要原則歸結為六個字:正確、准確、高效。
剪枝演算法按照其判斷思路可大致分成兩類:可行性剪枝及最優性剪枝。
對於分支定界演算法,上界是已求得的可行解的目標函數值中的最小者,分為初始上界和在探測過程中產生的動態上界.分支定界法在求最優解的迭代過程中, 若某結點估計的下界不小於已知的上界, 則不必從該節點往下繼續搜索. 因此若能產生一個較好的上界, 可以消除許多不必要的列舉計算.
分支定界演算法的實現
在描述分支定界演算法步驟之前, 先對演算法涉及到的有關術語進行定義如下:
p —— 分支層數;
C*—— 當前最優目標函數值;
P*—— 相應於C*的工件順序;
P1—— 當前節點(現在需要進行分支的節點)所對應的部分序列.
分支定界演算法的實施步驟如下:
步驟1 初始化: 設置p = 0, P 1 = Á (空集) , C* = ∞.設當前節點總是與P 1 相對應. 此時, 當前節點即根節點.
步驟2 計算從當前節點分支得到的各個子節點的下界, 並按下界值由小到大對各子節點排序. 令p ←p + 1.
步驟3 如果當前節點被探測盡, 令p ←p - 1, 轉步驟6. 否則, 設當前層(第p 層) 各活動子節點中具有最小下界值的節點為Q , 則在P 1末尾加入Q 對應第p 位置上的工件, 此時的當前節點轉為Q , 轉步驟4.
步驟4 因為當前節點是同層同父節點具有最小下界值的節點, 如果當前節點下界值大於或等於C* , 則不必再搜索當前節點及其同層同父的活動節點, 這樣, 當前節點的上一層節點(父節點)被探測盡, p ←p - 1, 去掉P 1 中的最後一個工件,轉步驟6. 否則, 轉步驟5.
步驟5 如果p = n, 則得到一個較優順序.令P* = P 1, C* 是當前節點的下界值, p ←p - 1,去掉P 1 中最後一個工件, 轉步驟6; 否則轉步驟2.
步驟6 若p ≠ 0, 去掉P 1 中最後一個工件,轉步驟3; 否則, 演算法停止. C* 是最優的目標函數值, P* 是最優順序.
分支結構演算法的實現(編程基礎)
我現在學到了分支結構了。又遇到問題了,不知道你還在不在,可以幫我嗎?(可以,沒問題.)
1、用Pascal語言表示下列的條件表達式:
(1):x小於10;
(2):0<=y<=5;(『小於等於』不會打)
(3):x大於5或x為負數;
(4):ch在「A」和「Z」之間(包括「A」和「Z」);
(5):年齡(age)不小於18,國籍(natioality)不是中國「CHINA」,也不是朝鮮「KOREA」的男性公民(sex=`maie`);
(6):正數,在2~100之間且不能被2,或3,或5整除。
2、試寫出下列各項的Pascal語句:
(1):如果wage大於10000,便減去10%的wage.
(2):如果Choice的值為1,則讀取x的值,並列印x的平方;否則讀取y的值,並列印y的平方。