【ybtoj 4.1 二叉堆课堂过关】A.合并果子【小根堆】

在这里插入图片描述
在这里插入图片描述
题目链接:合并果子

分析

很明显是每次合并两个最小的。
维护一个小根堆,每次取出两个最小的,将他们的和记录并放回堆。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,tree[30001],len,ans;

void put(int x)
{
	tree[++len]=x;//加到最后 
	int son=len;//当前位置 
	while(son>1) 
	{
		int fa=son/2;
		if(tree[fa]<tree[son]) break;//符合小根堆条件 
		else //否则继续往上移 
		{
			swap(tree[fa],tree[son]);
			son=fa;
		}
	}
}

int get()//不仅要取第一个,还要保证依然是小根堆 
{
	int t=tree[1];
	tree[1]=tree[len];
	len--;
	int fa=1;
	while(fa*2<=len)//保证有儿子 
	{
		int son=fa*2;//先求左儿子 
		if(tree[son]>tree[son+1]&&son+1<=len)
		{//比较两个儿子 
			son++;
		}
		if(tree[son]>tree[fa]) break;//如果比小儿子还小 
		else//否则小儿子作为父亲 
		{
			swap(tree[son],tree[fa]);
			fa=son;
		}
	}
	return t;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int a;
		cin>>a;
		put(a);
	}
	for(int i=1;i<n;i++)
	{
		int x=get(),y=get();//每次取出最小的(贪心) 
		ans+=(x+y);
	//	cout<<ans<<' '<<x<<' '<<y<<endl;
		put(x+y);//根据题意将和放进去继续准备合并 
	}
	cout<<ans;
	return 0;
}

Update on 2022.1.20

另一种建立堆的写法以及STL优先队列写法。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;

int n,a[100001],k,ans; 

void down(int x)
{
	int i=x;
	while(i*2<=n)
	{
		i*=2;
		if(a[i]>a[i+1]&&i+1<=n) i++;
		if(a[i/2]>a[i]) swap(a[i/2],a[i]);
		else break;
	}
}

int get()
{
	int t=a[1];
	a[1]=a[k];
	k--;
	int fa=1;
	while(fa*2<=k)
	{
		int son=fa*2; 
		if(a[son]>a[son+1]&&son+1<=k) son++;
		if(a[son]<a[fa])
		{
			swap(a[son],a[fa]);
			fa=son;
		 } 
		else break;
	} 
	return t;
}

void putup(int x)
{
	a[++k]=x;
	int now=k;
	while(now>1)
	{
		int fa=now/2;
		if(a[fa]>a[now])
		{
			swap(a[fa],a[now]);
			now=fa;
		}
		else break;
	}
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
	}
	for(int i=n/2;i>=1;i--)
	{
		down(i);//O(n)建堆
	}
	k=n;
	for(int i=1;i<=n-1;i++)
	{
		int x=get(),y=get();
		ans+=x+y;
		putup(x+y);
	}
	cout<<ans;
	return 0;
}

STL:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;

priority_queue<int> q;

int n,x,ans;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		q.push(-x);
	}
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		x=q.top();q.pop();
		y=q.top();q.pop();
		ans+=(-x-y);
		q.push(x+y);
	}
	cout<<ans;
	return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值