D e s c r i p t i o n Description Description
给出一个数列, 每次可以合并其中的两个,然后这两个数的和又会成为一个新的数(代价)存在于数列中,问最后数列中只剩一个数的时候,每次合并的代价的和(最小)是多少
I n p u t Input Input
输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
O u t p u t Output Output
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
S a m p l e Sample Sample I n p u t Input Input
3
1 2 9
S a m p l e Sample Sample O u t p u t Output Output
15
T r a i n Train Train o f of of T h o u g h t Thought Thought
其实就是建立一个小根堆,每次取出堆顶和堆顶的一个较小的儿子出来合并,合并出来的数再插入回堆中,直到最后堆中只剩下一个时,输出累计的答案
C o d e Code Code
#include<cstdio>
#include<iostream>
using namespace std;
int f[20005],n,t;
void Up(int x)
{
while ((x>1) && (f[x]<f[x/2]))
{
swap(f[x],f[x/2]);
x/=2;
}
}
void Down(int x)
{
while ((x*2<=t && f[x]>f[x*2]) || (f[x]>f[x*2+1] && x*2+1<=t))
{
int y=2*x;
if (y+1<=t && f[y+1]<f[y]) y++;
swap(f[x],f[y]);
x=y;
}
}
void Ins(int x)
{
f[++t]=x;
Up(t);
}
void Del(int x)
{
if (f[t]>f[x]) {
f[x]=f[t--];
Down(x);
}
else {
f[x]=f[t--];
Up(x);
}
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; ++i)
{
int x;
scanf("%d",&x);
Ins(x);
}
long long ans=0;
while (t>=2)
{
int p=f[1];
Del(1);
p+=f[1];
Del(1);
ans+=p;//保证堆顶一定是最小的
Ins(p);
}
printf("%lld",ans);
}