模板:堆排序_guanlovean的博客-CSDN博客_堆排序
原题:https://www.luogu.com.cn/problem/P1090
思路:关键在于每次找出最小的两个数相加。一下就想到了小顶堆,排一轮序就能完成计算复杂度为O(nlog2n)比O(n^2)强。具体细节见注释。
//小顶堆
#include<bits/stdc++.h>
using namespace std;
int arr[10010];
int n;
void swap(int a,int b)
{
int t=arr[a];
arr[a]=arr[b];
arr[b]=t;
}
//单个节点的调整
void heapify(int idx,int len)
{
int left=2*idx+1;
int right=2*idx+2;
int minidx=idx;
if(left<=len&&arr[left]<arr[minidx])minidx=left;
if(right<=len&&arr[right]<arr[minidx])minidx=right;
if(minidx!=idx)
{
//使子树三个节点成为小顶堆
swap(idx,minidx);
//由于子节点被换了,下面的节点可能不满足小顶堆了,继续换。
heapify(minidx,len);
}
}
//建堆
void buildheap()
{
//从后往前对每一个节点调整
for(int i=n-1;i>=0;i--)
{
heapify(i,n-1);
}
}
int main()
{
//输入数据
scanf("%d",&n);
int i;
int min=0;//用于暂存最小的数
long long ans=0;
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
//构建小顶堆
buildheap();
int len=n-1;
while(len>=0)
{
//如果min=0,说明只有一堆 不能两两并堆
//暂存此堆,并将最后一堆放到第一堆,删除第一堆
if(min==0)
{
min=arr[0];
arr[0]=0;
swap(0,len);
len--;
}
//如果min!=0,说明不止一堆,可以两两并堆,并计算体力
else if(min!=0)
{
//一次合成
arr[0]=min+arr[0];
ans+=arr[0];
min=0;
}
//对第一个节点进行调整
heapify(0,len);
}
printf("%lld",ans);
}