最優合並問題
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
給定k 個排好序的序列s1 , s2,……, sk , 用2 路合並算法將這k 個序列合並成一個序列。假設所采用的2 路合並算法合並2 個長度分別為m和n的序列需要m + n -1次比較。試設計一個算法確定合並這個序列的最優合並順序,使所需的總比較次數最少。
為了進行比較,還需要確定合並這個序列的最差合並順序,使所需的總比較次數最多。
對於給定的k個待合並序列,計算最多比較次數和最少比較次數合並方案。
Input
輸入數據的第一行有1 個正整數k(k≤1000),表示有k個待合並序列。接下來的1 行中,有k個正整數,表示k個待合並序列的長度。
Output
輸出兩個整數,中間用空格隔開,表示計算出的最多比較次數和最少比較次數。
Sample Input
4 5 12 11 2
Sample Output
78 52
Hint
Source
使用 優先隊列 優化 ,使用模板
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 template<typename T> 5 int result(T q){//使用模板 因為求最大 最小值 ,這兩個 代碼幾乎一樣 6 int rst=0; 7 while((int)q.size()>2){//兩個求和 8 int sum=0; 9 for(int i=0;i<2;i++){ 10 sum+=q.top(); 11 q.pop(); 12 } 13 rst+=sum; 14 q.push(sum); 15 } 16 while(!q.empty()){ 17 rst+=q.top(); 18 q.pop(); 19 } 20 return rst; 21 } 22 int main() 23 { 24 priority_queue<int,vector<int>,less<int> > q;//從大到小 Max 25 priority_queue<int,vector<int>,greater<int> > p;// 從小 到大 Min 26 int n,data; 27 cin>>n; 28 for(int i=0;i<n;i++){ 29 cin>>data; 30 q.push(data); 31 p.push(data); 32 } 33 int maxNum=result(q);//2 路合並算法合並2 個長度分別為m和n的序列需要m + n -1次比較 34 int minNum=result(p); 35 cout<<maxNum-(n-1)<<" "<<minNum-(n-1)<<endl;// 所以總共 比較n-1次 最后減去 n-1即可 36 return 0; 37 }
初始:未優化
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 priority_queue<int,vector<int>,less<int> > q;//從大到小 Max 6 priority_queue<int,vector<int>,greater<int> > p;// 從小 到大 Min 7 int n,data; 8 cin>>n; 9 for(int i=0;i<n;i++){ 10 cin>>data; 11 q.push(data); 12 p.push(data); 13 } 14 int maxNum=0;//初始化 最大 費用 0 15 int minNum=0;//初始化 最小 費用 0 16 while((int)q.size()>2){ 17 int sumMax=0,sumMin=0; 18 for(int i=0;i<2;i++){ 19 sumMax+=q.top(); 20 q.pop(); 21 sumMin+=p.top(); 22 p.pop(); 23 } 24 maxNum+=sumMax; 25 minNum+=sumMin; 26 q.push(sumMax); 27 p.push(sumMin); 28 } 29 while(!q.empty()){ 30 maxNum+=q.top(); 31 minNum+=p.top(); 32 q.pop(); 33 p.pop(); 34 } 35 cout<<maxNum-(n-1)<<" "<<minNum-(n-1)<<endl; 36 return 0; 37 }
使用數組
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 6 bool cmp(int a, int b){ 7 return a>b; 8 } 9 10 int main(){ 11 int k; 12 int a[1010], b[1010]; 13 int Min = 0, Max = 0;//此算法 ,和優先隊列 差不多,每次將 算出的 最小值,最大值,在放進隊列中 ,進行比較 14 cin>>k; 15 for(int i=0; i<k; i++){ 16 cin>>a[i]; 17 b[i]= a[i]; 18 }//當取最小值保證每次的2個加數為最小便可,最大值同理取當前最大的兩個值便可 19 sort(a, a+k);//最小值 排序 從小到大 20 sort(b, b+k, cmp);// 將 數據 從大到小 排序 21 for(int i=0; i<k-1; i++){ 22 a[i+1] = a[i]+a[i+1];//當前 開始的 下一個 值 替換為 前兩個 數之和, 23 Min += a[i+1];//最小值 更新 為 兩個 最小值 最后 才算了 -(k-1) 因為 k 個數 ,要進行 k-1次比較 ,得減去 k-1 個 1 ; k-1次 (m+n-1) 24 sort(a+i+1, a+k); 25 26 b[i+1] = b[i]+b[i+1];//此處為 最大值 ,每次加過 之和,在放進 要進行合並的序列中 在進行參與比較 27 Max += b[i+1]; 28 sort(b+i+1, b+k ,cmp); 29 } 30 cout<<Max-k+1<<' '<<Min-k+1<<endl; 31 return 0; 32 }
1 函數模板的聲明形式為: 2 template<typename(或class) T> 3 <返回類型><函數名>(參數表) 4 { 5 函數體 6 } 7 其中,template是定義模板函數的關鍵字;template后面的尖括號不能省略;typename(或class)是聲明數據類型參數標識符的關鍵字,用以說明它后面的標識符是數據類型標識符。這樣,在以后定義的這個函數中,凡希望根據實參數據類型來確定數據類型的變量,都可以用數據類型參數標識符來說明,從而使這個變量可以適應不同的數據類型。例如: 8 template<typename(或class) T> 9 T fuc(T x, T y) 10 { 11 T x; 12 //…… 13 }