導航:首頁 > 源碼編譯 > 最優設計准則與演算法

最優設計准則與演算法

發布時間:2022-05-17 07:52:30

1. 何謂演算法演算法有什麼性質

演算法(algorithm),在數學(算學)和計算機科學之中,為任何一系列良定義的具體計算步驟,常用於計算、數據處理和自動推理。作為一個有效方法,演算法被用於計算函數,它包含了一系列定義清晰的指令,並可於有限的時間及空間內清楚的表述出來。

特點:

1、輸入:一個演算法必須有零個或以上輸入量。

2、輸出:一個演算法應有一個或以上輸出量,輸出量是演算法計算的結果。

3、明確性:演算法的描述必須無歧義,以保證演算法的實際執行結果是精確地符合要求或期望,通常要求實際運行結果是確定的。

4、有限性:依據圖靈的定義,一個演算法是能夠被任何圖靈完備系統模擬的一串運算,而圖靈機只有有限個狀態、有限個輸入符號和有限個轉移函數(指令)。而一些定義更規定演算法必須在有限個步驟內完成任務。

5、有效性:又稱可行性。能夠實現,演算法中描述的操作都是可以通過已經實現的基本運算執行有限次來實現。

(1)最優設計准則與演算法擴展閱讀:

常用設計模式

完全遍歷法和不完全遍歷法:在問題的解是有限離散解空間,且可以驗證正確性和最優性時,最簡單的演算法就是把解空間的所有元素完全遍歷一遍,逐個檢測元素是否是我們要的解。

這是最直接的演算法,實現往往最簡單。但是當解空間特別龐大時,這種演算法很可能導致工程上無法承受的計算量。這時候可以利用不完全遍歷方法——例如各種搜索法和規劃法——來減少計算量。

1、分治法:把一個問題分割成互相獨立的多個部分分別求解的思路。這種求解思路帶來的好處之一是便於進行並行計算。

2、動態規劃法:當問題的整體最優解就是由局部最優解組成的時候,經常採用的一種方法。

3、貪心演算法:常見的近似求解思路。當問題的整體最優解不是(或無法證明是)由局部最優解組成,且對解的最優性沒有要求的時候,可以採用的一種方法。

4、簡並法:把一個問題通過邏輯或數學推理,簡化成與之等價或者近似的、相對簡單的模型,進而求解的方法。

2. 結構優化設計的基本方法

數學規劃法的命題是:求n個變數xi(i=l,2,…,n),滿足m個約束條件Gj(xi)≤0 (j=l,2,…,m),且使目標函數W(xi)為最小(或最大)。如果約束條件和目標函數都是xi的線性函數,這便是線性規劃問題,已有成熟的解法;如果在這些函數中有一個是非線性函數,便成為非線性規劃問題。隨著非線性函數的性質和形式的不同,非線性規劃問題有很多類型,特殊的解法很多,在應用上各有局限性,沒有普遍適用的最好解法。
用數學規劃法來作結構優化設計,變數xi便代表可以變化的各種結構參數,如元件截面積或厚度、節點位置、材料性質等;約束條件Gj(xi)≤0代表設計必須滿足的各種限制,例如結構各部位的靜應力,動應力或變位不得超過規定的容許值,元件的截面或厚度尺寸不得超出給定的范圍,結構的頻率不應落在某個禁區,結構的失穩臨界力或飛行器的顫振速度不得小於某一下限,等等;而目標函數則代表結構優化所追求的指標,例如,結構重量最小和成本最低等可以定量的指標;也可將重量、造價作為約束條件,而把某種結構性能,例如剛度作為目標函數。
數學規劃法的基本目的是,在以設計變數為坐標的多維空間里搜索最優點。如果有n個設計變數,則相應的n維設計變數空間中的每個點都代表一個設計方案。在無限多的點中要盡快地搜索出既滿足所有的約束條件,又能使目標函數盡量接近最小值(或最大值)的點,就是數學規劃設計法的任務,這種搜索的過程稱為「優化過程」。
附圖表示一個二維設計空間,圖中的一簇曲線是目標函數W(x1,x2)為常數的等值線。約束函數Gj(x1,x2)為零的曲線所圍成的區域是可行域。A、B、C點各代表一個可行的方案.圍線以外的點(如D)不滿足約束條件,所以是不可行方案。顯然,滿足約束條件並使目標函數W最小的最優方案點是M。數學規劃就是要以最迅速的方式找到點M。這好比在山坡上—個用柵欄圍起來的區域里找最低點,如果這個山坡不是凹的,則可以斷定最低點必在柵欄所在的邊界上。數學規劃提供了很多搜索的辦法,基本原則都是在選好一個出發點後,經過分析判斷,找出一個邁步的有利方向,沿這個方向跨出有利的步長以到達新的一點。再從此點出發,重復上述過程,一步一步走下去,直到再也找不到可走的有利方向,就是達到了最低點。從第n點到第(n+1)點這一步可表達為:
式中 為有利方向, 為有利步長系數,它們依靠在點進行的分析所提供的信息來確定。例如,從可行點A出發,沿著等高線的梯度負向,即最陡下降方向逐步走到邊界點1,然後再沿著邊界逐步走到最低點M,這個方法叫作梯度投影法。實際上還有很多其他的方法。可以看出,如果初始出發點選的是B,用同樣的走法也可以走到最低點M;但如果初始點選的是C,那就會走到另一個局部最低點N。M點代表全局最優解,因為它是全部可行域中的最低點。N點只是在它附近的可行域中的最低點,所以是局部最優解。現在還沒有一個可靠的實用方法能保證搜索到的解一定是全局最優解。一般是在可能的情況下取若干不同的出發點作幾次搜索,以期找到全局最優解。
如果是線性規劃問題,搜索過程就簡便得多。所以有時把非線性問題轉化成一系列線性問題來逼近。為此,在某一設計點附近將目標函數和約束函數都線性化,也就是在該點將函數作泰勒展開,並只保留它們的線性項。然後作有一定步長限制的線性規劃,得到新的一點。如此重復下去,直到收斂於最優點為止。
由於不帶約束的規劃問題比較容易作,所以有時也把有約束問題轉化成一個序列的無約束問題。為此,可以把約束表示成一個罰函數加到目標函數上去,構成一個新的目標函數,即
式中 即為罰函數,r是個相當小的正數,它在序列無約束問題中,逐次減小。因為r值很小,當代表某一設計方案的點在離開邊界較遠的可行域內部行動時,;但是當接近可行域的邊界.某約束函數Gj(xi)將由負值趨近於零,於是罰函數急劇增大,因此,的最小點不可能越過可行域邊界。r越小,無約束問題的W最小點越接近於有約束問題的W最小點。但是如果一開始就取很小的r,無約束問題將遇到收斂上的困難,所以有必要將有約束問題化成一個序列的無約束問題,讓系數r在這個序列中逐漸減小到適當的程度。
此外,還有一些非線性規劃的特殊方法,如幾何規劃和動態規劃,各有其適應的范圍,在結構優化設計中也得到應用。 以滿足某種准則來代替目標函數在約束條件下取極值的方法,叫作優化准則法。最簡單的一個優化准則法,便是前面提到的滿應力設計方法。只有對於內力分布不隨設計變數改變而變化的靜定結構,而且容許應力與設計變數無關的情況下,才能通過一次結構分析和修改設計得出滿應力結構。對於其他情況,為使各元件趨向於滿應力,必須進行下列的選代:

式中 和 為第n次迭代的第i元件的截面積和最大應力, 為第i元件的容許應力。公式給出經過修正的第i元件的截面積 。迭代收斂時, ,就達到 的滿應力准則。滿應力准則和結構最小重量之間沒有必然的聯系,但是一般的滿應力設計可能相當接近於甚至就等於最輕設計。當然,這個方法只適用於受應力約束的最輕設計問題。
60年代末,出現了更科學的優化准則法。它通過數學推演,把在一定約束下求最輕設計化為求滿足某種優化准則的設計,舉只有一個變位約束優化設計問題為例:求xi,滿足在單約束G(xi)≤0的條件下,使W(xi)最小(i=1,2,…,n)。可以用目標函數和約束函數建立一個新的混合函數,即拉格朗日函數:

式中λ為一個待定的拉格朗日乘子。原來的約束極值問題等價於:

由此得:

這便是關於單約束優化設計必須滿足的准則。優化設計x,必須使優化函數和目標函數對任一個設計變數xi的偏導數的比值是同一個常數。如果約束函數G是某處的變位,則 表示設計變數xi作單位增長時變位值的減小,即結構的剛度收益;如果目標函數W是結構的總重量,則 表示xi作單位增長時重量的增加,即付出的代價。因此,上述准則可以理解為:最輕設計必須滿足的條件是:當任何一個自由設計變數作單位變化時,結構的剛度收益和重量支出的比值應彼此相等,即都等於某一常數。也可以說,在最輕結構中,自由設計變數都被調整到具有相等的優化效率。這意味著對結構剛度貢獻大的設計變數,應該多負點重量。用這個准則,可以建立一套迭代演算法,從某個初始方案開始,用選代方法逐步使這個准則得到滿足,最後獲得優化方案。如果是多約束問題,約束不止一個,優化准則便是:

式中λj是對應於第j個有效約束Gi的拉格朗日乘子,可以理解為:

的權系數。所有λj都應為非負值,即λj≥0;如果由准則算出的某λj為負值,則相應的約束就是不起作用的松約束,應該取這個λj為零值。多約束的演算法,要比單約束復雜,其困難在於每一步選代都要區別出起作用的和不起作用的約束。
優化准則法自60年代末以來被成功地用於航空結構設計。它的優點是演算法簡單,收斂快,不受變數多少的影響。一般經過十次左右的迭代,就可滿足設計要求。選代次數的多少,在實際的結構優化設計中極為重要。因為選代一次,就需要將結構重新分析一次,而作一次結構分析的代價是很大的。

3. 設計演算法的原則

設計演算法的原則:

1、正確性:演算法的正確性是指演算法至少應該具有輸入、輸出和加工處理無歧義性、能正確反映問題的需要、能夠得到問題的正確答案。

2、可讀性:設計演算法的目的,一方面是為了讓計算機執行,但還有一個重要的目的就是為了便於他人的閱讀,讓人理解和交流,自己將來也可閱讀。如果可讀性不好,時間長了自己都不知道寫了什麼,可讀性是評判演算法(也包括實現它的程序代碼)好壞很重要的標志。

3、健壯性:當輸入的數據非法時,演算法應當恰當地做出反應或進行相應處理,而不是莫名其妙的輸出結果。並且處理出錯的方法不應是中斷程序的執行,而應是返回一個表示錯誤或錯誤性質的值,以便於在更高的抽象層次上進行處理。

4、高效率與低存儲量:通常,演算法的效率指的是演算法的執行時間;演算法的存儲量指的是演算法執行過程中所需要的最大存儲空間,兩者的復雜度都與問題的規模有關。演算法分析的任務是對設計的每一個具體的演算法,利用數學工具,討論其復雜度,探討具體演算法對問題的適應性。

(3)最優設計准則與演算法擴展閱讀:

演算法的「正確」通常在用法上有很大的差別,大體分為以下4個層次:

1、演算法程序沒有語法錯誤;

2、演算法程序能夠根據正確的輸入的值得到滿足要求的輸出結果;

3、演算法程序能夠根據錯誤的輸出的值滿足規格說明的輸出結果;

4、演算法程序對於精心設計、極其刁難的測試數據都能滿足要求的輸出結果。

對於這4層含義,層次要求最低,因為僅僅沒有語法錯誤實在談不上是好的演算法。而層次(4)是最困難的,人們幾乎不可能逐一驗證所有的輸入都得到正確的結果。因此,演算法的正確性在大部分情況下都不可能用程序來證明,而是用數學方法證明的。

4. 結構優化設計的方法簡介

1.簡單解法
當優化問題的變數較少時,可用下列簡單解法。
(1)圖解法。在設計空間中作出可行域和目標函數等值面,再從圖形上找出既在可行域內(或其邊界內),又使目標函數值最小的設計點的位置。
(2)解析法。當問題比較簡單時,可用解析法求解。
2.准則法
准則法是從工程和力學觀點出發,提出結構達到優化設計時應滿足的某些准則(如同步失效准則、滿應力准則、能量准則等),然後用迭代的方法求出滿足這些准則的解。該方法的主要特點是收斂快,重分析次數與設計變數數目無直接關系,計算量不大,但適用有局限性,主要適用於結構布局及幾何形狀已定的情況。盡管准則法有它的缺點,但從工程應用的角度來看,它比較方便,習慣上易於接受,優點仍是主要的。最簡單的准則法有同步失效准則法和滿應力准則法。
(1)同步失效准則法。其基本思想可概括為:在荷載作用下,能使所有可能發生的破壞模式同時實現的結構是最優的結構。同步失效准則設計有許多明顯的缺點。由於要用解析表達式進行代數運算,同步失效設計只能用來處理非常簡單的元件優化;當約束數大於設計變數數時,必須設法確定那些破壞模式應當同時發生才給出最優設計,這通常是一件十分困難的工作;當約束數和設計變數數相等時,並不能保證這樣求得的解是最優解。
(2)滿應力准則法。該法認為充分發揮材料強度的潛力,可以算是結構優化的一個標志,以桿件滿應力作為優化設計的准則。這一方法在桿件系統如桁架的優化設計中用得較多。在此基礎上又發展了與射線步結合的齒行法以及框架等復雜結構的滿應力設計。
3.數學規劃法
將結構優化問題歸納為一個數學規劃問題,然後用數學規劃法來求解。結構優化中常用的數學規劃方法是非線性規劃,有時也用線性規劃,特殊情況可能用到動態規劃、幾何規劃、整數規劃或隨機規劃等。
(1)線性規劃。當目標函數和約束方程都是設計變數的線性函數時,稱為線性規劃問題。該類問題的解法比較成熟,其中常用的解法是單純形法。
(2)非線性規劃。當目標函數或約束方程為設計變數的非線性函數時,稱為非線性規劃。結構優化設計多為有約束的非線性規劃問題。這類問題較線性規劃問題復雜得多,難度較大,目前採用的方法大致有以下幾種類型:不作轉換但需求導數的分析方法,如梯度投影法、可行方向法等;不作轉換也不需求導數的直接搜索方法,如復形法;採用線性規劃來逐次逼近,如序列線性規劃法;轉換為無約束極值問題求解,如罰函數法、乘子法等。
4.混合法
混合法即同時採用准則法和數學規劃法。
5.啟發式演算法
近些年來發展起來了一些啟發式演算法。這些演算法有遺傳演算法(GA)、神經網路演算法、模擬退火演算法等。它們在結構優化領域得到了一些應用。

5. 高層建築結構優化演算法有哪幾種

高層建築結構優化演算法:
①優化准則法一從直觀的力學原理出發,選定使結構達到最優的准則,然後根據這些准則選取適當的迭代格式,尋求結構的最優解。
②數學規劃法一從解極值問題的數學原理出發,運用數學規劃方法求得一系列設計參數的最優解。
結構優化設計:
在給定約束條件下,按某種目標(如重量最輕、成本最低、剛度最大等)求出最好的設計方案,曾稱為結構最佳設計或結構最優設計,相對於「結構分析」而言,又稱「結構綜合」;如以結構的重量最小為目標,則稱為最小重量設計。

6. 優化設計演算法的收斂准則有哪些

點距准則
函數下降量准則
梯度准則

7. 演算法設計原則是什麼

原則:首先說設計的演算法必須是"正確的",其次應有很好的"可讀性",還必須具有"健壯性",最後應考慮所設計的演算法具有"高效率與低存儲量"。

所謂演算法是正確的,除了應該滿足演算法說明中寫明的"功能"之外,應對各組典型的帶有苛刻條件的輸入數據得出正確的結果。

在演算法是正確的前提下,演算法的可讀性是擺在第一位的,這在當今大型軟體需要多人合作完成的環境下是換重要的,另一方面,晦澀難讀的程序易於隱藏錯誤而難以調試。演算法的效率指的是演算法的執行時間,演算法的存儲量指的是演算法執行過程中所需最大存儲空間。

演算法是程序設計的另一個不可缺的要素,因此在討論數據結構的同時免不了要討論相應的演算法。這里有兩重意思,即演算法中的操作步驟為有限個,且每個步驟都能在有限時間內完成。

確定性表現在對演算法中每一步的描述都沒有二義性,只要輸入相同,初始狀態相同,則無論執行多少遍,所得結果都應該相同。

可行性指的是,序列中的每個操作都是可以簡單完成的,其本身不存在演算法問題,例如,"求x和y的公因子"就不夠基本。

輸入值即為演算法的操作對象,但操作的對象也可以由演算法自身生成,如"求100以內的素數",操作對象是自然數列,可以由變數逐個增1生成。

演算法的健壯性指的是,演算法應對非法輸入的數據作出恰當反映或進行相應處理,一般情況下,應向調用它的函數返回一個表示錯誤或錯誤性質的值。

8. 統計學中什麼是最優設計原則

樓主理解正確。單因素實驗確定的最佳工藝條件是局部最優,而正交表確定的最佳工藝條件是綜合各因素下的最優,兩者不一定重合,而全局最優條件需要通過計算確定,後進行驗證。

9. 衡量演算法效率的方法與准則

演算法效率與分析
數據結構作為程序設計的基礎,其對演算法效率的影響必然是不可忽視的。本文就如何合理選擇數據結構來優化演算法這一問題,對選擇數據結構的原則和方法進行了一些探討。首先對數據邏輯結構的重要性進行了分析,提出了選擇邏輯結構的兩個基本原則;接著又比較了順序和鏈式兩種存儲結構的優點和缺點,並討論了選擇數據存儲結構的方法;最後本文從選擇數據結構的的另一角度出發,進一步探討了如何將多種數據結構進行結合的方法。在討論方法的同時,本文還結合實際,選用了一些較具有代表性的信息學競賽試題舉例進行了分析
【正文】一、引論
「數據結構+演算法=程序」,這就說明程序設計的實質就是對確定的問題選擇一種合適的數據結構,加上設計一種好的演算法。由此可見,數據結構在程序設計中有著十分重要的地位。
數據結構是相互之間存在一種或多種特定關系的數據元素的集合。因為這其中的「關系」,指的是數據元素之間的邏輯關系,因此數據結構又稱為數據的邏輯結構。而相對於邏輯結構這個比較抽象的概念,我們將數據結構在計算機中的表示又稱為數據的存儲結構。
建立問題的數學模型,進而設計問題的演算法,直至編出程序並進行調試通過,這就是我們解決信息學問題的一般步驟。我們要建立問題的數學模型,必須首先找出問題中各對象之間的關系,也就是確定所使用的邏輯結構;同時,設計演算法和程序實現的過程,必須確定如何實現對各個對象的操作,而操作的方法是決定於數據所採用的存儲結構的。因此,數據邏輯結構和存儲結構的好壞,將直接影響到程序的效率。

二、選擇合理的邏輯結構

在程序設計中,邏輯結構的選用就是要分析題目中的數據元素之間的關系,並根據這些特定關系來選用合適的邏輯結構以實現對問題的數學描述,進一步解決問題。邏輯結構實際上是用數學的方法來描述問題中所涉及的操作對象及對象之間的關系,將操作對象抽象為數學元素,將對象之間的復雜關系用數學語言描述出來。
根據數據元素之間關系的不同特性,通常有以下四種基本邏輯結構:集合、線性結構、樹形結構、圖狀(網狀)結構。這四種結構中,除了集合中的數據元素之間只有「同屬於一個集合」的關系外,其它三種結構數據元素之間分別為「一對一」、「一對多」、「多對多」的關系。
因此,在選擇邏輯結構之前,我們應首先把題目中的操作對象和對象之間的關系分析清楚,然後再根據這些關系的特點來合理的選用邏輯結構。尤其是在某些復雜的問題中,數據之間的關系相當復雜,且選用不同邏輯結構都可以解決這一問題,但選用不同邏輯結構實現的演算法效率大不一樣。
對於這一類問題,我們應採用怎樣的標准對邏輯結構進行選擇呢?
下文將探討選擇合理邏輯結構應充分考慮的兩個因素。

一、 充分利用「可直接使用」的信息。
首先,我們這里所講的「信息」,指的是元素與元素之間的關系。
對於待處理的信息,大致可分為「可直接使用」和「不可直接使用」兩類。對於「可直接使用」的信息,我們使用時十分方便,只需直接拿來就可以了。而對於「不可直接使用」的這一類,我們也可以通過某些間接的方式,使之成為可以使用的信息,但其中轉化的過程顯然是比較浪費時間的。
由此可見,我們所需要的是盡量多的「可直接使用」的信息。這樣的信息越多,演算法的效率就會越高。
對於不同的邏輯結構,其包含的信息是不同的,演算法對信息的利用也會出現不同的復雜程度。因此,要使演算法能夠充分利用「可直接使用」的信息,而避免演算法在信息由「不可直接使用」向「可直接使用」的轉化過程中浪費過多的時間,我們必然需要採用一種合理的邏輯結構,使其包含更多「可直接使用」的信息。
〖問題一〗 IOI99的《隱藏的碼字》。
〖問題描述〗
問題中給出了一些碼字和一個文本,要求編程找出文本中包含這些碼字的所有項目,並將找出的項目組成一個最優的「答案」,使得答案中各項目所包含的碼字長度總和最大。每一個項目包括一個碼字,以及該碼字在文本中的一個覆蓋序列(如』abcadc』就是碼字』abac』的一個覆蓋序列),並且覆蓋序列的長度不超過1000。同時,「答案」要求其中每個項目的覆蓋序列互相沒有重疊。
〖問題分析〗
對於此題,一種較容易得出的基本演算法是:對覆蓋序列在文本中的終止位置進行循環,再判斷包含了哪些碼字,找出所有項目,並最後使用動態規劃的方法將項目組成最優的「答案」。
演算法的其它方面我們暫且不做考慮,而先對問題所採用的邏輯結構進行選擇。
如果我們採用線性的邏輯結構(如循環隊列),那麼我們在判斷是否包含某個碼字t時,所用的方法為:初始時用指針p指向終止位置,接著通過p的不斷前移,依次找出碼字t從尾到頭的各個字母。例如碼字為「ABDCAB」,而文本圖1-1,終止位置為最右邊的箭頭符號,每個箭頭代表依次找到的碼字的各個字母。
指針p的移動方向
A B D C A B

C D A C B D C A D C D B A D C C B A D

圖1-1

由於題目規定碼字的覆蓋序列長度不超過1000,所以進行這樣的一次是否包含的判斷,其復雜度為O(1000)。
由於碼字t中相鄰兩字母在文本中的位置,並非只有相鄰(如圖1-1中的』D』和』C』)這一種關系,中間還可能間隔了許多的字母(如圖1-1中』C』和』A』就間隔了2個字母),而線性結構中擁有的信息,僅僅只存在於相鄰的兩元素之間。通過這樣簡單的信息來尋找碼字的某一個字母,其效率顯然不高。
如果我們建立一個有向圖,其中頂點i(即文本的第i位)用52條弧分別連接』a』..』z』,』A』..』Z』這52個字母在i位以前最後出現的位置(如圖1-2的連接方式),我們要尋找碼字中某個字母的前一個字母,就可以直接利用已連接的邊,而不需用枚舉的方法。我們也可以把問題看為:從有向圖的一個頂點出發,尋找一條長度為length(t)-1的路徑,並且路徑中經過的頂點,按照碼字t中的字母有序。

C D A C B D C A D C D B A D C C B A D

圖1-2
通過計算,用圖進行記錄在空間上完全可以承受(記錄1000個點×52條弧×4位元組的長整型=200k左右)。在時間上,由於可以充分利用第i位和第i+1位弧的連接方式變化不大這一點(如圖1-2所示,第i位和第i+1位只有一條弧的指向發生了變化,即第i+1位將其中一條弧指向了第i位),所以要對圖中的弧進行記錄,只需對弧的指向進行整體賦值,並改變其中的某一條弧即可。
因此,我們通過採用圖的邏輯結構,使得尋找字母的效率大大提高,其判斷的復雜度為O(length(t)),最壞為O(100),比原來方法的判斷效率提高了10倍。
(附程序codes.pas)

對於這個例子,雖然用線性的數據結構也可以解決,但由於判斷的特殊性,每次需要的信息並不能從相鄰的元素中找到,而線性結構中只有相鄰元素之間存在關系的這一點,就成為了一個很明顯的缺點。因此,問題一線性結構中的信息,就屬於「不可直接使用」的信息。相對而言,圖的結構就正好滿足了我們的需要,將所有可能產生關系的點都用弧連接起來,使我們可以利用弧的關系,高效地進行判斷尋找的過程。雖然圖的結構更加復雜,但卻將「不可直接使用」的信息,轉化成為了「可直接使用」的信息,演算法效率的提高,自然在情理之中。。
二、 不記錄「無用」信息。
從問題一中我們看到,由於圖結構的信息量大,所以其中的信息基本上都是「可用」的。但是,這並不表示我們就一定要使用圖的結構。在某些情況下,圖結構中的「可用」信息,是有些多餘的。
信息都「可用」自然是好事,但倘若其中「無用」(不需要)的信息太多,就只會增加我們思考分析和處理問題時的復雜程度,反而不利於我們解決問題了。
〖問題二〗 湖南省1997年組隊賽的《乘船問題》
〖問題描述〗
有N個人需要乘船,而每船最多隻能載兩人,且必須同名或同姓。求最少需要多少條船。
〖問題分析〗
看到這道題,很多人都會想到圖的數據結構:將N個人看作無向圖的N個點,凡同名或同姓的人之間都連上邊。
要滿足用船最少的條件,就是需要盡量多的兩人共乘一條船,表現在圖中就是要用最少的邊完成對所有頂點的覆蓋。這就正好對應了圖論的典型問題:求最小邊的覆蓋。所用的演算法為「求任意圖最大匹配」的演算法。
使用「求任意圖最大匹配」的演算法比較復雜(要用到擴展交錯樹,對花的收縮等等),效率也不是很高。因此,我們必須尋找一個更簡單高效的方法。
首先,由於圖中任兩個連通分量都是相對獨立的,也就是說任一條匹配邊的兩頂點,都只屬於同一個連通分量。因此,我們可以對每個連通分量分別進行處理,而不會影響最終的結果。
同時,我們還可以對需要船隻s的下限進行估計:
對於一個包含Pi個頂點的連通分量,其最小覆蓋邊數顯然為[Pi/2]。若圖中共有L個連通分量,則s=∑[Pi/2](1<=i<=L)。
然後,我們通過多次嘗試,可得出一個猜想:
實際需要的覆蓋邊數完全等於我們求出的下限∑[Pi/2](1<=i<=L)。
要用圖的結構對上述猜想進行證明,可參照以下兩步進行:
1. 連通分量中若不存在度為1的點,就必然存在迴路。
2. 從圖中刪去度為1的點及其相鄰的點,或刪去迴路中的任何一邊,連通分量依然連通,即連通分量必然存在非橋邊。
由於圖的方法不是這里的重點,所以具體證明不做詳述。而由採用圖的數據結構得出的演算法為:每次輸出一條非橋的邊,並從圖中將邊的兩頂點刪去。此演算法的時間復雜度為O(n3)。(尋找一條非橋邊的復雜度為O(n2),尋找覆蓋邊操作的復雜度為O(n))
由於受到圖結構的限制,時間復雜度已經無法降低,所以如果我們要繼續對演算法進行優化,只有考慮使用另一種邏輯結構。這里,我想到了使用二叉樹的結構,具體說就是將圖中的連通分量都轉化為二叉樹,用二叉樹來解決問題。
首先,我們以連通分量中任一個頂點作為樹根,然後我們來確定建樹的方法。
1. 找出與根結點i同姓的點j(j不在二叉樹中)作為i的左兒子,再以j為樹根建立子樹。
2. 找出與根結點i同名的點k(k不在二叉樹中)作為i的右兒子,再以k為樹根建立子樹。
如圖2-1-1中的連通分量,我們通過上面的建樹方法,可以使其成為圖2-1-2中的二叉樹的結構(以結點1為根)。(兩點間用實線表示同姓,虛線表示同名)

圖2-1-2

圖2-1-1
接著,我就來證明這棵樹一定包含了連通分量中的所有頂點。
【引理2.1】
若二叉樹T中包含了某個結點p,那麼連通分量中所有與p同姓的點一定都在T中。
證明:
為了論證的方便,我們約定:s表示與p同姓的頂點集合;lc[p,0]表示結點p,lc[p,i](i>0)表示lc[p,i-1]的左兒子,顯然lc[p,i]與p是同姓的。
假設存在某個點q,滿足qs且qT。由於s是有限集合,因而必然存在某個lc[p,k]無左兒子。則我們可以令lc[p,k+1]=q,所以qT,與假設qT相矛盾。
所以假設不成立,原命題得證。

由引理2.1的證明方法,我們同理可證引理2.2。
【引理2.2】
若二叉樹T中包含了某個結點p,那麼連通分量中所有與p同名的點一定都在T中。

有了上面的兩個引理,我們就不難得出下面的定理了。
【定理一】
以連通分量中的任一點p作為根結點的二叉樹,必然能夠包含連通分量中的所有頂點。
證明:
由引理2.1和引理2.2,所有與p同姓或同名的點都一定在二叉樹中,即連通分量中所有與p有邊相連的點都在二叉樹中。由連通分量中任兩點間都存在路徑的特性,該連通分量中的所有點都在二叉樹中。

在證明二叉樹中包含了連通分量的所有頂點後,我們接著就需要證明我們的猜想,也就是下面的定理:
【定理二】包含m個結點的二叉樹Tm,只需要船的數量為boat[m]=[m/2](mN)。
證明:
(i) 當m=1,m=2,m=3時命題顯然成立。

圖2-2-1

圖2-2-2

圖2-2-3
(ii) 假設當m<k(k>3)時命題成立,那麼當m=k時,我們首先從樹中找到一個層次最深的結點,並假設這個結點的父親為p。那麼,此時有且只有以下三種情況(結點中帶有陰影的是p結點):
(1) 如圖2-2-1,p只有一個兒子。此時刪去p和p唯一的兒子,Tk就成為了Tk-2,則boat[k]=boat[k-2]+1=[(k-2)/2]+1=[k/2]。
(2) 如圖2-2-2,p有兩個兒子,並且p是其父親的左兒子。此時可刪去p和p的右兒子,並可將p的左兒子放到p的位置上。同樣地,Tk成為了Tk-2,boat[k]=boat[k-2]+1=[k/2]。
(3) 如圖2-2-3,p有兩個兒子,並且p是其父親的右兒子。此時可刪去p和p的左兒子,並可將p的右兒子放到p的位置上。情況與(2)十分相似,易得此時得boat[k]=boat[k-2]+1=[k/2]。
綜合(1)、(2)、(3),當m=k時,boat[k]=[k/2]。
最後,綜合(i)、(ii),對於一切mN,boat[m]=[m/2]。

由上述證明,我們將問題中數據的圖結構轉化為樹結構後,可以得出求一棵二叉樹的乘船方案的演算法:
proc try(father:integer;var root:integer;var rest:byte);
{輸出root為樹根的子樹的乘船方案,father=0表示root是其父親的左兒子,
father=1表示root是其父親的右兒子,rest表示輸出子樹的乘船方案後,
是否還剩下一個根結點未乘船}
begin
visit[root]:=true; {標記root已訪問}
找到一個與root同姓且未訪問的結點j;
if j<>n+1 then try(0,j,lrest);
找到一個與root同姓且未訪問的結點k;
if k<>n+1 then try(1,k,rrest);
if (lrest=1) xor (rrest=1) then begin {判斷root是否只有一個兒子,情況一}
if lrest=1 then print(lrest,root) else print(rrest,root);
rest:=0;
end
else if (lrest=1) and (rrest=1) then begin {判斷root是否有兩個兒子}
if father=0 then begin
print(rrest,root);root:=j; {情況二}
end
else begin
print(lrest,root);root:=k; {情況三}
end;
rest:=1;
end
else rest:=1;
end;

這只是輸出一棵二叉樹的乘船方案的演算法,要輸出所有人的乘船方案,我們還需再加一層循環,用於尋找各棵二叉樹的根結點,但由於每個點都只會訪問一次,尋找其左右兒子各需進行一次循環,所以演算法的時間復雜度為O(n2)。(附程序boat.pas)

最後,我們對兩種結構得出不同時間復雜度演算法的原因進行分析。其中最關鍵的一點就是因為二叉樹雖然結構相對較簡單,但已經包含了幾乎全部都「有用」的信息。由我們尋找乘船方案的演算法可知,二叉樹中的所有邊不僅都發揮了作用,而且沒有重復的使用,可見信息的利用率也是相當之高的。
既然採用樹結構已經足夠,圖結構中的一些信息就顯然就成為了「無用」的信息。這些多餘的「無用」信息,使我們在分析問題時難於發現規律,也很難找到高效的演算法進行解決。這正如迷宮中的牆一樣,越多越難走。「無用」的信息,只會干擾問題的規律性,使我們更難找出解決問題的方法。

小結
我們對數據的邏輯結構進行選擇,是構造數學模型一大關鍵,而演算法又是用來解決數學模型的。要使演算法效率高,首先必須選好數據的邏輯結構。上面已經提出了選擇邏輯結構的兩個條件(思考方向),總之目的是提高信息的利用效果。利用「可直接使用」的信息,由於中間不需其它操作,利用的效率自然很高;不不記錄「無用」的信息,就會使我們更加專心地研究分析「有用」的信息,對信息的使用也必然會更加優化。
總之,在解決問題的過程中,選擇合理的邏輯結構是相當重要的環
三、 選擇合理的存儲結構
數據的存儲結構,分為順序存儲結構和鏈式存儲結構。順序存儲結構的特點是藉助元素在存儲器中的相對位置來表示數據元素之間的邏輯關系;鏈式存儲結構則是藉助指示元素存儲地址的指針表示數據元素之間的邏輯關系。
因為兩種存儲結構的不同,導致這兩種存儲結構在具體使用時也分別存在著優點和缺點。
這里有一個較簡單的例子:我們需要記錄一個n×n的矩陣,矩陣中包含的非0元素為m個。
此時,我們若採用順序存儲結構,就會使用一個n×n的二維數組,將所有數據元素全部記錄下來;若採用鏈式存儲結構,則需要使用一個包含m個結點的鏈表,記錄所有非0的m個數據元素。由這樣兩種不同的記錄方式,我們可以通過對數據的不同操作來分析它們的優點和缺點。
1. 隨機訪問矩陣中任意元素。由於順序結構在物理位置上是相鄰的,所以可以很容易地獲得任意元素的存儲地址,其復雜度為O(1);對於鏈式結構,由於不具備物理位置相鄰的特點,所以首先必須對整個鏈表進行一次遍歷,尋找需進行訪問的元素的存儲地址,其復雜度為O(m)。此時使用順序結構顯然效率更高。
2. 對所有數據進行遍歷。兩種存儲結構對於這種操作的復雜度是顯而易見的,順序結構的復雜度為O(n2),鏈式結構為O(m)。由於在一般情況下m要遠小於n2,所以此時鏈式結構的效率要高上許多。
除上述兩種操作外,對於其它的操作,這兩種結構都不存在很明顯的優點和缺點,如對鏈表進行刪除或插入操作,在順序結構中可表示為改變相應位置的數據元素。
既然兩種存儲結構對於不同的操作,其效率存在較大的差異,那麼我們在確定存儲結構時,必須仔細分析演算法中操作的需要,合理地選擇一種能夠「揚長避短」的存儲結構。

一、合理採用順序存儲結構。
我們在平常做題時,大多都是使用順序存儲結構對數據進行存儲。究其原因,一方面是出於順序結構操作方便的考慮,另一方面是在程序實現的過程中,使用順序結構相對於鏈式結構更便於對程序進行調試和查找錯誤。因此,大多數人習慣上認為,能夠使用順序結構進行存儲的問題,最「好」採用順序存儲結構。
其實,這個所謂的「好」只是一個相對的標准,是建立在以下兩個前提條件之下的:
1. 鏈式結構存儲的結點與順序結構存儲的結點數目相差不大。這種情況下,由於存儲的結點數目比較接近,使用鏈式結構完全不能體現出記錄結點少的優點,並且可能會由於指針操作較慢而降低演算法的效率。更有甚者,由於指針自身佔用的空間較大,且結點數目較多,因而演算法對空間的要求可能根本無法得到滿足。
2. 並非演算法效率的瓶頸所在。由於不是演算法最費時間的地方,這里是否進行改進,顯然是不會對整個演算法構成太大影響的,若使用鏈式結構反而會顯得操作過於繁瑣。

二、必要時採用鏈式存儲結構。
上面我對使用順序存儲結構的條件進行了分析,最後就只剩下何時應該採用鏈式存儲結構的問題了。
由於鏈式結構中指針操作確實較繁瑣,並且速度也較慢,調試也不方便,因而大家一般都不太願意用鏈式的存儲結構。但是,這只是一般的觀點,當鏈式結構確實對演算法有很大改進時,我們還是不得不進行考慮的。
〖問題三〗 IOI99的《地下城市》。
〖問題描述〗
已知一個城市的地圖,但未給出你的初始位置。你需要通過一系列的移動和探索,以確定初始時所在的位置。題目的限制是:
1. 不能移動到有牆的方格。
2. 只能探索當前所在位置四個方向上的相鄰方格。
在這兩個限制條件下,要求我們的探索次數(不包括移動)盡可能的少。
〖問題分析〗
由於存儲結構要由演算法的需要確定,因此我們首先來確定問題的演算法。
經過對問題的分析,我們得出解題的基本思想:先假設所有無牆的方格都可能是初始位置,再通過探索一步步地縮小初始位置的范圍,最終得到真正的初始位置。同時,為提高演算法效率,我們還用到了分治的思想,使我們每一次探索都盡量多的縮小初始位置的范圍(使程序盡量減少對運氣的依賴)。
接著,我們來確定此題的存儲結構。
由於這道題的地圖是一個二維的矩陣,所以一般來講,採用順序存儲結構理所當然。但是,順序存儲結構在這道題中暴露了很大的缺點。我們所進行的最多的操作,一是對初始位置的范圍進行篩選,二是判斷要選擇哪個位置進行探索。而這兩種操作,所需要用到的數據,只是龐大地圖中很少的一部分。如果採用順序存儲結構(如圖3-1中陰影部分表示已標記),無論你需要用到多少數據,始終都要完全的遍歷整個地圖。

4
3
2
1
1 2 3 4
圖3-1

head

圖3-2
然而,如果我們採用的是鏈式存儲結構(如圖3-2的鏈表),那麼我們需要多少數據,就只會遍歷多少數據,這樣不僅充分發揮了鏈式存儲結構的優點,而且由於不需單獨對某一個數據進行提取,每次都是對所有數據進行判斷,從而避免了鏈式結構的最大缺點。
我們使用鏈式存儲結構,雖然沒有降低問題的時間復雜度(鏈式存儲結構在最壞情況下的存儲量與順序存儲結構的存儲量幾乎相同),但由於體現了前文所述選擇存儲結構時揚長避短的原則,因而演算法的效率也大為提高。(程序對不同數據的運行時間見表3-3)
測試數據編號 使用順序存儲結構的程序 使用鏈式存儲結構的程序
1 0.06s 0.02s
2 1.73s 0.07s
3 1.14s 0.06s
4 3.86s 0.14s
5 32.84s 0.21s
6 141.16s 0.23s
7 0.91s 0.12s
8 6.92s 0.29s
9 6.10s 0.23s
10 17.41s 0.20s

表3-3
(附使用鏈式存儲結構的程序under.pas)
我們選擇鏈式的存儲結構,雖然操作上可能稍復雜一些,但由於改進了演算法的瓶頸,演算法的效率自然也今非昔比。由此可見,必要時選擇鏈式結構這一方法,其效果是不容忽視的。
小結
合理選擇邏輯結構,由於牽涉建立數學模型的問題,可能大家都會比較注意。但是對存儲結構的選擇,由於不會對演算法復雜度構成影響,所以比較容易忽視。那麼,這種不能降低演算法復雜度的方法是否需要重視呢?
大家都知道,剪枝作為一種常用的優化演算法的方法,被廣泛地使用,但剪枝同樣是無法改變演算法的復雜度的。因此,作用與剪枝相似的存儲結構的合理選擇,也是同樣很值得重視的。
總之,我們在設計演算法的過程中,必須充分考慮存儲結構所帶來的不同影響,選擇最合理的存儲結構。

四、 多種數據結構相結合

上文所探討的,都是如何對數據結構進行選擇,其中包含了邏輯結構的選擇和存儲結構的選擇,是一種具有較大普遍性的演算法優化方法。對於多數的問題,我們都可以通過選擇一種合理的邏輯結構和存儲結構以達到優化演算法的目的。
但是,有些問題卻往往不如人願,要對這類問題的數據結構進行選擇,常常會顧此失彼,有時甚至根本就不存在某一種合適的數據結構。此時,我們是無法選擇出某一種合適的數據結構的,以上的方法就有些不太適用了。
為解決數據結構難以選擇的問題,我們可以採用將多種數據結構進行結合的方法。通過多種數據結構相結合,達到取長補短的作用,使不同的數據結構在演算法中發揮出各自的優勢。
這只是我們將多種數據結構進行結合的總思想,具體如何進行結合,我們可以先看下面的例子。
我們可以採用映射的方法,將線性結構中的元素與堆中間的結點一一對應起來,若線性的數組中的元素發生變化,堆中相應的結點也接著變化,堆中的結點發生變化,數組中相應的元素也跟著變化。
將兩種結構進行結合後,無論是第一步還是第二步,我們都不需對所有元素進行遍歷,只需進行常數次復雜度為O(log2n)的堆化操作。這樣,整個時間復雜度就成為了O(nlog2n),演算法效率無疑得到了很大提高。

五、 總結
我們平常使用數據結構,往往只將其作為建立模型和演算法實現的工具,而沒有考慮這種工具對程序效率所產生的影響。信息學問題隨著難度的不斷增大,對演算法時空效率的要求也越來越高,而演算法的時空效率,在很大程度上都受到了數據結構的制約。

10. 演算法的設計原則是什麼

1.窮舉演算法思想

窮舉演算法思想就是從所有的可能結果中一個一個的試驗,知道試出正確的結果。具體的操作步驟如下:

1)對每一種可能的結果,計算其結果;

2)判斷結果是否符合題目要求,如果符合則該結果正確,如果不符合則繼續進行第1)步驟。

窮舉演算法思想的經典例子為雞兔同籠為題(又稱龜鶴同籠問題),題目為「一個籠子里有雞兔,共15個頭、46條腿,問雞兔各有多少只?」。代碼如下:

public static void main(String[] args) {

int head = 0;
int leg = 0;
System.out.println( "輸入雞兔頭數:");
Scanner input=new Scanner(System.in);
head = input.nextInt();
System.out.println( "輸入雞兔腿數:");
Scanner input1=new Scanner(System.in);
leg = input1.nextInt();

boolean existence = false;
for( int i = 0; i <= head; i++){
if( 2 * i + 4 * ( head - i) == leg){
System.out.println( "雞的個數 :" + i);
System.out.println( "兔的個數 :" + ( head - i));
existence = true;
}
}

if( !existence){
System.out.println( "你輸入的數據不正確");
}
}

2.遞推演算法思想

遞推演算法演算法就是根據已知條件,利用特定關系推導出中間推論,直到得到結果的演算法。

遞推演算法思想最經典的例子是斐波那契數列 : 1,1,2,3,5,8,13......

上面的數列符合F(n) = F(n-1) + F(n-2).代碼如下:

public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n = input.nextInt();
System.out.println( fibonacci( n));
}

public static int fibonacci( int n){
if( n == 1){
return 1;
}else if( n == 2){
return 1;
}else{
return fibonacci( n - 1) + fibonacci( n - 2);
}
}

3.遞歸演算法思想

遞歸演算法思想是把大問題轉換成同類問題的子問題,然後遞歸調用函數表示問題的解。

在使用遞歸的時候一定要注意調回遞歸函數的終止條件。

遞歸演算法比較經典的例子是求階乘。代碼如下:

public static void main(String[] args) {
System.out.println( "輸入一個大於零的數:");
Scanner input=new Scanner(System.in);
int n = input.nextInt();
System.out.println( factorial( n));
}

public static int factorial( int n){
if( n == 0){
return 1;
}else if( n == 1){
return 1;
}else{

閱讀全文

與最優設計准則與演算法相關的資料

熱點內容
雲桌面卡是因為伺服器的原因嗎 瀏覽:377
qd123壓縮機 瀏覽:969
pn532讀取加密門禁卡 瀏覽:85
win10文件夾屬性里無法加密 瀏覽:34
比特幣加密的條件 瀏覽:848
求購現成影視app源碼 瀏覽:572
wdsecurity加密版 瀏覽:813
雲伺服器和雲豐雲 瀏覽:188
伺服器如何設置獨立ip 瀏覽:857
tar命令打包文件夾 瀏覽:1000
刪除linux用戶和組 瀏覽:548
小米的程序員都用什麼筆記本 瀏覽:703
位元組三面演算法題 瀏覽:971
伺服器保護有什麼好處 瀏覽:894
全部下載完後進行統一解壓 瀏覽:393
遠嫁的程序員媽媽 瀏覽:555
1024程序員節安全攻防挑戰賽 瀏覽:786
怎麼解除txt加密 瀏覽:772
javahttp流 瀏覽:656
交叉編譯工具前綴是什麼 瀏覽:528