演算法第四章上機實踐報告

2022-08-22 14:51:12 字數 3125 閱讀 4814

引論:相比與動態規劃演算法,貪心演算法是比較容易理解的,其思想就在於得到當前狀態下區域性最好選擇,當乙個問題的最優解包含其子問題的最優解時,即每個貪心選擇都是子問題的最優解,那麼就能的到該問題的最優解了。本次上機實踐的題目雖然不是特別難,但相比前兩次,這一次上機實踐的效率遠低於上兩次,因為在實踐的時候被第二題難住了,就沒有去思考第三題,導致進度大大落後。既然如此,那麼本篇部落格就以第三題為例來講解貪心演算法吧。

給定k 個排好序的序列, 用 2 路合併演算法將這k 個序列合併成乙個序列。 假設所採用的 2 路合併演算法合併 2 個長度分別為m和n的序列需要m+n-1 次比較。試設 計乙個演算法確定合併這個序列的最優合併順序,使所需的總比較次數最少。 為了進行比較,還需要確定合併這個序列的最差合併順序,使所需的總比較次數最多。

第一行有 1 個正整數k,表示有 k個待合併序列。 第二行有 k個正整數,表示 k個待合併序列的長度。

輸出最多比較次數和最少比較次數。

在這裡給出一組輸入。例如:

4

5 12 11 2

在這裡給出相應的輸出。例如:

78 52

要解決本題,首先要理解題目中提及的 2 路合併演算法,其意思是將含m和n個數字的陣列合併,則需要m + n - 1 次比較,得到的是乙個含m + n個數字的新陣列。給出了k個陣列,那麼就要進行k - 1次2路合併,例如題目的輸入樣例給出了4個陣列,那麼就需要進行3次合併。而又因為各陣列的數字數目不同,則合併時進行的比較次數也不同,因此需要找到乙個合適的合併順序使得總比較次數最少和最多。所以,本題的解題關鍵是:找到合併陣列的順序!

首先列出我解題的**

1 #include 2 #include 3

using

namespace

std;45

intmain()616

17 priority_queue , greater > tempqueue; //

定義小頂堆

18 priority_queue largequeue; //

定義大頂堆

1920

for (int i = 0; i < n; i++) //

存陣列中的數字入堆

2125

2627

28int min = 0; //

min表示最少比較總次數

29int max = 0; //

max表示最多比較總次數

3031

while (true) //

求最少次數

3243

else

4447}48

49while (true) //

求最多次數

5061

else

6265}66

67 cout << max << "

"<68return0;

69 }

題目要求是求出最少和最多的總比較次數,結合我們求哈夫曼樹的經驗,那麼如果想得到最少的總比較次數,那麼就需要選出給定的最短的陣列,先進行二路合併,得到新陣列,再比較新陣列和其餘陣列,再次挑出2個最短的陣列,直到只剩下乙個陣列即為最少總比較次數陣列。相反,若想得到比較次數最多,那麼我們按照相同的思想,只需要把挑出兩個最短的改為挑出兩個最長的,直到只剩下乙個陣列即為最多總比較次數陣列。恰好這個解題思路很適合使用標頭檔案中內建的資料結構——優先佇列priority_queue

priority_queue  (變數名)    //

預設為最小的元素為堆頂

當我們讓優先佇列的頭元素出佇列時,優先佇列是自動排好序的,即保持最小的元素保持在隊頭,這樣我們每次只需要取出佇列頭元素,並出佇列,再取出第二個佇列頭,進行二路合併,即能達成我們保持合併兩個最短佇列的思想。

下面用反證法來證明最優子結構策略:(由於求出最少比較次數與最多比較次數類似,所以這裡以全球除最少比較次數為例)

設a 與 b 陣列是給出的最短陣列,其數目分別為m 與 n,合併兩個陣列的比較次數為 m + n - 1, 得出的新陣列的長度為 m + n。 若還有兩個陣列c 與 d , 他們的數目分別為i 與 j,合併次數為 i + j - 1, 則得出的陣列長度為i + j。 而整個問題的最優解還需要在長度為i + j的陣列與剩餘的陣列(設長度為k)二路合併,但由於陣列a 與b是原有的最短的陣列, 即 m + n - 1 < i + j - 1,且 m + n + k < i + j + k,則導致求出的最優解不是整個問題的最優解,與求出總最少比較次數矛盾。(大問題的最優解包含子問題的最優解)

用反證法來證明貪心選擇:

先挑選出原有陣列的最短的兩個陣列(長度為 n 與 m),比較次數為c1 = n + m - 1,合併後的陣列長度為(n + m);再挑選出剩下的陣列和長度為n + m的陣列中最短的兩個進行二路合併, 若第二次合併是長度為i的陣列與第一次合併得出的陣列合併,則比較次數c2 = n + m + i - 2。若有兩個陣列合併後的長度為 k < n + m,合併它所比較的次數為 q < n + m - 1,第二次合併的比較次數為 q + i,那麼總比較次數包含 q + i,但由於不存在該兩個陣列,得出矛盾。所以本問題的最優解是通過先求出n + m - 1 再得出 n + m + i - 2,再一步步就能得出大問題的最優解。(整體最優解可以通過一系列區域性最優的選擇)

對於時間複雜度: 本演算法的核心部分為求最少比較次數和最多比較次數的兩個while迴圈,while迴圈的結束取決於優先佇列的長度。根據給進隊的迴圈,則本演算法的時間複雜度為o(n)。

對於空間複雜度:由於用到了兩個優先佇列來分別表示大頂堆和小頂堆(用到了tempqueue和largequeue),所以空間複雜度為t(2n) = o(n)。

通過本次實踐,我感觸最深的就是其實貪心演算法的策略我們一直都在使用,貪心演算法並不是什麼特別難懂的演算法,只需要我們找到貪心選擇的策略,再證明它是否可行,證明可行後使用貪心演算法能夠有效又高效率地解決問題。這次結對程式設計效果沒有上一次的好,原因在於我們的思維限制在了一點上,其實可以兩個人分別想出不同的貪心策略再檢驗是否可行,當一種策略不可行就馬上換下一種。還有不足就是我還不能很好地證明自己的貪心選擇策略,不能有理有據地向大家展示出來,導致自己做題的時候覺得可行,但其實自己也不太清楚其原因。

演算法第四章上機實踐報告

1.實踐題目 4 1 程式儲存問題 設有n 個程式要存放在長度為l的磁帶上。程式i存放在磁帶上的長度是 li,1 i n。程式儲存問題要求確定這n 個程式在磁帶上的乙個儲存方案,使得能夠在磁帶上儲存盡可能多的程式。對於給定的n個程式存放在磁帶上的長度,計算磁帶上最多可以儲存的程式數。2.問題描述 在...

第四章演算法上機實踐報告

第四章演算法上機實踐報告 實踐題目 設有n 個程式要存放在長度為l的磁帶上。程式i存放在磁帶上的長度是 li,1 i n。程式儲存問題要求確定這n 個程式在磁帶上的乙個儲存方案,使得能夠在磁帶上儲存盡可能多的程式。對於給定的n個程式存放在磁帶上的長度,計算磁帶上最多可以儲存的程式數。輸入格式 第一行...

演算法第四章上機實踐報告

一 實踐題目 程式儲存問題 設有n 個程式要存放在長度為l的磁帶上。程式i存放在磁帶上的長度是 li,1 i n。程式儲存問題要求確定這n 個程式在磁帶上的乙個儲存方案,使得能夠在磁帶上儲存盡可能多的程式。對於給定的n個程式存放在磁帶上的長度,計算磁帶上最多可以儲存的程式數。第一行是2 個正整數,分...