luogu1090:合并果子:过程排序+求最小值

93 篇文章 0 订阅
78 篇文章 0 订阅
题目要求对一个序列不断取最小两数相加并放回序列,直至只剩一个数,求所有中间和。通过堆排序实现每次找到最小两数,记录总和。代码实现详细解析。
摘要由CSDN通过智能技术生成

题目连接:该题是luogu试炼场的2-6:T1


题目大意:

1 给n个数字的序列,(每次取最小的两个相加,得到新的数字),这个数字再放回原序列,直到序列里只有一个数;
2 求:过程中产生的和的总量;
3 例如:
                原序列为:1 2 3 5;
1+2=3:  新序列为:3 3 5;
3+3=6:  新序列为:5 6;
5+6=11:新序列为:11.
所以答案是:3+6+11=20.


解题思路:
1 因为数字是可以随意调换顺序的,所以每次都是要找最小值出来,因此想到了堆;
2 用一个堆来维护这些数字,每次取最小值,然后把加好的新值放回堆中;
3 直到堆里值剩下一个元素,记录过程的和就好了。


上代码:
 

//luogu1181:数列分段 

//解题思路:
//1 一用一个堆维护最小值 
//2 每次取最小的两个值相加
//3 直到全部合并
 
#include<cstdio>
#include<cstring>

int n;
int a[10010];

void sdown(int x)//向下的维护堆 
{
	int f,s,t=x;
	f=x; s=f*2;
	if(s<=n && a[f]>a[s]) t=s; //问 左儿子 
	if(s+1<=n && a[t]>a[s+1]) t=s+1;//问 右儿子 
	
	if(t!=x) //要交换 
	{
		int k=a[f]; a[f]=a[t]; a[t]=k;
		sdown(t);
	} 
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	
	for(int i=n/2;i>=1;i--) //建堆 
	{
		sdown(i);
	}
	
	int ans=0,k;
	
	while(n>1)//堆还有多个元素 
	{
		k=0;
		ans+=a[1]; k+=a[1]; //拿第一个数 
		
		a[1]=a[n]; n--; sdown(1); //维护
		 
		ans+=a[1]; k+=a[1]; //拿第二个数
		
		a[1]=k; sdown(1); //维护
	}
	
	printf("%d",ans);

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值