演算法第四章上機實踐報告
阿新 • • 發佈:2018-11-28
一、實踐題目
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).
心得體會:
通過本次實踐操作,對貪心演算法的理解更加深刻,知道該如何分析貪心策略來求得所需要的答案,希望能通過不斷練習更進一步。