[CodeVs 1063] 合并果子 ——小根堆

CodeVs 1063
/*
首先理解小(大)根堆的概念
即将数据以树的结构处理
小根堆: 每个父节点都比其叶子小
大根堆: 每个父节点都比其叶子大

这样,保证了这组数据较为有序,且根节点毕竟为最值
然后取最值,并删除这个数【处理方法为覆盖为最后一个数】,再次维护一下根节点,不断重复,即实现了堆排序

然后以CodeVs 1063 「合并果子」这道经典题来看这种最小堆的实际用途
分析:
基础思路肯定为贪心,不断取最小的两个合并,得到的肯定为最小的
然而合并过后得到的值还要放回去,则仍需要排序维护以得到最小两个
因此建立小根堆,放回去后只需维护其所选择的那个节点便行了 
*/
#include<bits/stdc++.h>
using namespace std;
int Many,Stack[10000];
void Swap(int, int, int);
void Mainten(int Top, int Tail)		//建立小根堆
{
	if (Top*2 > Tail) return; 		//没有儿子,直接退出 
	if (Top*2+1 > Tail)				//只有左儿子 
	{
		if (Stack[Top] > Stack[Top*2]) Swap(Top,Top*2,Tail);}
	else
	{								//左右儿子都有,取最小放上去 
		int MinTop=Stack[Top*2]<Stack[Top*2+1]?Top*2:Top*2+1;
		if (Stack[Top] > Stack[MinTop]) Swap(Top,MinTop,Tail);
	}
}
void Swap(int A, int B, int Tail)
{
	int t=Stack[A];
	Stack[A]=Stack[B],Stack[B]=t;
	Mainten(B,Tail);				//交换了后,一定要记得维护,注意这里是上至下维护,因此后面会有个易错点 
}
int main()
{
	cin >> Many;
	int Tail=Many,Ans=0;
	for (int i=1; i<=Many; i++) cin >> Stack[i];
	if (Many == 1) cout << Stack[1];
	sort(Stack+1,Stack+1+Many);								//刚开始可以直接sort,跟堆排效果一样的…… 
	for (int i=1; i<=Many-1; i++)
	{
		int Top=Stack[2]>Stack[3]&&Tail>2?3:2;				//这里比较根节点的左右儿子选择最小值
															//易错: 一定要判断是否堆里剩余个数大于2个,即根节点左右儿子均有,不然肯定出错,【选择了不存在的右儿子 
		Ans+=Stack[1]+Stack[Top];							//然后合并最小的两个,并累加到结果ans里 
		
		Stack[1]=Stack[1]+Stack[Top];						//将所合并的覆盖回去 
		Stack[Top]=Stack[Tail];								//将最后一个覆盖到所选的左右儿子
															//因为是选择了其中两个,然后要放回一个,便是以上操作 
		Tail--;												//结合这步,成功删除了两个用过的最小值,并将计算结果放回到堆中
		 
		Mainten(Top,Tail);									//这两步维护最小堆 
		Mainten(1,Tail);									//易错!: 一定要倒着,先维护Top在维护根,因为维护操作中我是更改顺序后只调整儿子节点,即可能第一个小于第二个第三个,但第二个不一定小于第五个第六个,但换了之后不会维护其父亲 
	}
	if (Ans != 0) cout << Ans;								//如果Many == 1的话ans会是零,这里加个特判点 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值