1. 程式人生 > >演算法第四章上機實踐報告

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

一、實踐題目

7-1 最優合併問題

題目描述:存在k個排好的序列,要用二路合併演算法將其合併成一個序列。將長度

為m和長度為n的序列合併需要比較m+n-1次,現在要求進行合併操作時,所需要的

總比較次數最多和最少的次數。輸入k,接下來的k個數為k個序列的長度

樣例1:

//輸入
4
5 12 11 2 
//輸出 78 52

題目分析:

容易分析得出,如果每次都將長度最小的兩個序列合併,則每次合併的比較次數都會是最小的,

不斷合併至為一個序列時,所需要的比較總次數最小。相反如果每次都將長度最大的兩個序列

合併,則每次合併的比較次數都是最大的,最後得到的比較次數最多。

實現:

由題目分析可知,需要不斷的將序列進行排序,因為每次合併後就會出現一個新的序列,又要將

新序列放入舊序列中重新排序,然後取出最小兩個值再次合併,直到序列中僅存在一個值,則表

示合併完成。由上述分析可知,可以將序列長度按升序排序和降序排序然後不斷合併在更新,就

可以得出結果因為需要不斷排序,顯然這裡可以利用大根堆和小根堆進行操作,即可以借用C++

STL中的優先佇列實現,定義優先順序之後,每次取出佇列中前兩個元素合併並且用一個變數累加記

錄比較次數,然後在將合併後的序列入隊,不斷進行該操作,直到佇列中的只存在一個元素為止。

程式碼:

#include<iostream>
#include
<queue> using namespace std; priority_queue<int>que; //大根堆 priority_queue<int,vector<int>,greater<int> >que1; //小根堆 int a; int main() { int n; cin>>n; for(int i=0;i<n;i++) { cin>>a; que.push(a); que1.push(a); }
int ans1=0; while(que.size()>1) { int a=que.top();que.pop(); //取出隊首兩個元素 int b=que.top();que.pop(); ans1+=(a+b-1); //記錄比較次數 que.push(a+b); //合併後的新序列入隊 } int ans2=0; while(que1.size()>1) { int a=que1.top();que1.pop(); int b=que1.top();que1.pop(); ans2+=(a+b-1); que1.push(a+b); } cout<<ans1<<' '<<ans2<<endl; }

演算法複雜度分析:

空間複雜度:改程式通過兩個佇列來實現,因此空間複雜度為O(n)。

時間複雜度:優先佇列入隊的時間複雜度為O(logN),共有k個序列需要進行(k-1)次入隊,因此時間複雜度為O(nlogn).

心得體會:

通過本次實踐操作,對貪心演算法的理解更加深刻,知道該如何分析貪心策略來求得所需要的答案,希望能通過不斷練習更進一步。