B - 多元Huffman编码问题 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 Output 593 199 Hint 请注意数据范围是否可能爆 int。
AC代码:
代码语言:javascript复制#include<bits/stdc .h>
using namespace std;
int main()
{
priority_queue<int,vector<int>,greater<int> >q1;//优先队列(从小到大)
priority_queue<int>q2;//优先队列(默认从大到小)
int n,k;
cin>>n>>k;
for(int i =0; i<n; i )
{
int x;
cin>>x;
q1.push(x);
q2.push(x);
}
while(q1.size()%(k-1)!=1)
q1.push(0);
long long sum_ma =0,sum_mi =0;
while(q1.size()>1)
{
long long sum = 0;
for(int i=0; i<k; i )
{
sum =q1.top();
q1.pop();
}
sum_mi =sum;
q1.push(sum);
}
while(q2.size()>1)
{
int a =q2.top();
q2.pop();
int b =q2.top();
q2.pop();
sum_ma =a b;
q2.push(a b);
}
cout<<sum_ma<<" "<<sum_mi<<endl;
}超时代码(只用做思路理解)
代码语言:javascript复制#include<bits/stdc .h>
using namespace std;
long long res_a = 0,res_b = 0;
int st[100001];
int st2[100001];
int re(int a,int b)
{
return a>b;
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=0; i<n; i )
{
cin>>st[i];
st2[i]=st[i];
}
//max值求解
sort(st,st n,re);
for(int i=1; i<n; i )
{
st[i] = st[i-1];
res_a = st[i];
sort(st i,st n,re);
}
// cout<<res_a<<endl;
//min值求解
//前p 1个数先合并
int p =(n-1)%(k-1);//余2走3 余1走2
if(p)//不余,没有预合并
{
sort(st2,st2 n);
int j =0;
while(j<=p)
{
res_b = st2[j];
j ;
}
st2[p] = res_b;
}
sort(st2 p,st2 n);//开始k组k组合并
for(int i = p k-1; i < n; i =k-1)
{
int j =i-1;
while(j >= i -k 1)
{
st2[i] = st2[j];
j--;
}
// cout<<st2[i]<<endl;
res_b = st2[i];
sort(st2 i,st2 n);
}
cout<<res_a<<" "<<res_b<<endl;
}思路:对于可以正好k组合并的就每次k组合并;如果不能保证每次都可以k组合并, 如下: 15 7 4 71 13 98 13 8 30 12 45 84 15 23 17 51 55
(1)先k组合并 最后合并三个,代价超过1000 (2)先合并三个,再k组合并代价更低 总代价698
代码语言:javascript复制4 8 12 13 13 15 17 23 30 45 51 55 71 84 98 24 第一次三个
13 13 15 17 23 24 30 45 51 55 71 84 98 135
45 51 55 71 84 98 135 539
539 (3)先合并两个,再k组合并呢, 总代价1090,显然不是最小
代码语言:javascript复制4 8 12 13 13 15 17 23 30 45 51 55 71 84 98 12 先一次2个
12 12 13 13 15 17 23 30 45 51 55 71 84 98 105
30 45 51 55 71 84 98 105 434
105 434 539
539可见,找到第一次,预先合并的数量很关键,超时可能是排序导致的,仅供思路理解!!! 总结: 求最大代价,就更慢用更多步去得到,每次取两个(两个最大),越靠后,合并的代价越高 求最低代价,减少步数,最理想的是每次合并都是k堆一合并(k为一次最大合并允许数,k个最小的),减缓代价上升的趋势, 即,( ( 1 (k-1) ) (k-1) (k-1) ) , 对于不能每次正好k次合并的,添0,保证第二次合并开始都是k个(理由和原因—见超时代码的举例)


