Problem Description
在一個操場的四周擺放着n堆石子。現要將石子有次序地合併成一堆。規定每次至少選2 堆最多選k堆石子合併成新的一堆,合併的費用爲新的一堆的石子數。試設計一個算法,計算出將n堆石子合併成一堆的最大總費用和最小總費用。
對於給定n堆石子,計算合併成一堆的最大總費用和最小總費用。
Input
輸入數據的第1 行有2 個正整數n和k(n≤100000,k≤10000),表示有n堆石子,每次至少選2 堆最多選k堆石子合併。第2 行有n個數(每個數均不超過 100),分別表示每堆石子的個數。
Output
將計算出的最大總費用和最小總費用輸出,兩個整數之間用空格分開。
Sample Input
7 3 45 13 12 16 9 5 22
Sample Output
593 199
最大的花費,就要找最大的數重疊次數最多,所以與K無關,只需要從最大的開始每次都選最大的兩堆來相加就可以得出最大的重疊次數。
最小的花費思路和最大的相同,要重迭次數最小,就要挑選K最大,每次從最小的K堆,開始合併。這裏要做一步處理是如果最後不夠K堆合併的時候要在整個隊列的前面填0(填零的意思就是一開始不按照K堆合併,而是按照從0-K的一個數合併,這樣後面的數重疊次數纔是最小的,如果不補零,後面大的數就會多重疊)。
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
priority_queue <int> q1; //構建最大優先隊列 百度一下優先隊列很簡單
priority_queue <int, vector<int>, greater<int> > q2;//構建最小優先隊列
int n, i, a, k;
cin>>n>>k;
for(i = 0; i < n; i++)
{
cin >> a;
q1.push(a);
q2.push(a);
}
long long minn = 0, maxx = 0;
long long sum1 = 0, sum2 = 0;
while(q2.size() % (k - 1) != 1)
{
q2.push(0);
}
while(q2.size() > 1)
{
sum2 = 0;
for(i = 0; i < k; i++)
{
sum2 += q2.top();
q2.pop();
}
minn += sum2;
q2.push(sum2);
}
while(q1.size() > 1)
{
sum1 = 0;
for(i = 0; i < 2; i++)
{
sum1 += q1.top();
q1.pop();
}
maxx += sum1;
q1.push(sum1);
}
cout<<maxx<<' '<<minn<<endl;
return 0;
}