Educational Codeforces Round 31-k叉哈夫曼&优先队列&好题-D. Boxes And Balls
程序员文章站
2022-06-04 18:51:31
...
http://codeforces.com/contest/884/problem/D
给定一个n。
然后是n个不同颜色的球的数目。
开始这些球都在第一个盒子里。
你有下面的操作方法
① 把某一个不空盒子种的球拿出来。
② 把这些球按颜色装到3个或者2个盒子里,不同颜色可以装在一起。
而每次这种操作的花费为 你第一个操作拿出的球的数目。
问你如何操作,能够使花费最小。
一点都不显然,这时一个k叉哈夫曼,我也是画图才发现。随着哈夫曼树叉树的增加,他的最小带权路径长度也再慢慢变小。但是编码所需字符集也在慢慢增多。所以这道题就是构造三叉哈夫曼就阔以了。
k叉哈夫曼的构造方法(by 大佬):
构造的思路。
每次选择最小的k个来放置。
但是容易发现最后可能不够k个,那怎么办捏
假设有n个节点,k叉,最后剩一个。
容易得到,n-1是k-1的倍数。
如果(n-1)%(k-1)!=0,
那么就要再放入(k-1-(n-1)%(k-1))个虚拟点,
并且它们的权值为0,它们也参与求最小k个点。
其实就是加点了。
#include <bits/stdc++.h>
using namespace std;
/*
*/
typedef long long ll;
struct cmp{
bool operator()(ll x,ll y){
return x>y;
}
};
priority_queue<ll,vector<ll>,cmp>q;
int t;
ll a;
int main() {
while(~scanf("%d",&t)){
ll sum=0;
while(!q.empty()) q.pop();
for(int i=0;i<t;i++){
scanf("%lld",&a);
q.push(a);
}
if((t-1)%2!=0){
int x=(2-(t-1)%2);
for(int i=0;i<x;i++)
q.push(0);
}
while(q.size()>=3){
ll a=0;
ll u1=q.top();q.pop();
a+=u1;
ll u2=q.top();q.pop();
a+=u2;
ll u3=q.top();q.pop();
a+=u3;
sum+=a;
q.push(a);
}
printf("%lld\n",sum);
}
return 0;
}
有巨佬的写法貌似不是这样,但是思路是一样的,大佬没有加点,但是在剩余节点为偶数的情况下选择只取2个最小的。(其实是一样的,经过我手算发现只有偶数的第一次可以出现这种情况,而也只有这种情况是加0 的,并且只加一个0,巧了,另一个大佬的代码就是酱紫,根据t的奇偶性,如果是偶数就加一个qwq)