洛谷 1880合并果子

2 篇文章 0 订阅
1 篇文章 0 订阅

这道题的做法有很多种,嘻嘻

1、贪心(好像几个月前就这样AC的)

排序是必须的,(我们不可能盲目的合并任意两堆石子)因为按照最小石子合并得到的最后答案一定是最小的;可以考虑用两个数组来分别存放合并了的石子堆和未合并的石子堆(b[ ]和a[ ]);

然后我们比较当前没有合并的石子堆中的前两个和合并了的石子堆中的一个,比较合并哪两个石子堆会得到最小值;

代码如下:

#include<bits/stdc++.h>
using namespace std;
bool cmp(const int &a,const int &b){
	return a<b;
}
int a[10005],b[10005],n; 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
	    cin>>a[i];
	sort(a+1,a+n+1,cmp);
	int i=1,j=1,m=0,t,ans=0;
	for(int q=1;q<=n-1;q++){
		if(j>m || j<=m && i<=n && a[i]<b[j])
		    t=a[i++];
		else
		    t=b[j++];
		if(j>m || j<=m && i<=n && a[i]<b[j])
		    t+=a[i++];
		else
		    t+=b[j++];
		ans+=t;
		b[++m]=t;
	}
	cout<<ans;
	
	return 0;
}

2、优先队列

也是排序的思路,但是这里利用了优先队列的性质,不论元素在队列中的那个位置,即使是在队尾,如果他优先级最高,要他出队也得出队。所以我们只需要每次都出两个元素,并将这两个元素合并的一个新石子堆的值跳到队中,就完成了一次合并;

由于n堆石子要合并n-1次才能剩下最后一堆,所以循环次数为n-1;

代码如下:

#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;
priority_queue< int , vector<int> , greater<int> > q;
int a,x,y,n,ans;
void init(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a;
		q.push(a);
	}
} 
int work(){
	for(int i=1;i<n;i++){
		x=q.top();q.pop();
		y=q.top();q.pop();
		ans+=x+y;
		q.push(x+y);
	}
	return ans;
}
int main(){
	init();
	cout<<work();
	return 0;
} 

3、堆

这里用的是小根堆,还是利用了数据结构的性质——最小的最先出,思路和优先队列差不多(取堆+取堆+存堆);

若要了解小(大)根堆,点击:http://blog.csdn.net/pngynghay/article/details/22052737

代码如下:

手写堆:

#include<bits/stdc++.h>
using namespace std;
const int N=10000+5;
int a[N],size,heap[N],n,ans;
void put(int x){
	heap[++size]=x;
	int now=size,nxt;
	while(now>1){
		nxt=now>>1;
		if(heap[now]>heap[nxt]) return;
		heap[now]^=heap[nxt]^=heap[now]^=heap[nxt];
		now=nxt;
	}
}
void init(){
	cin>>n;
	for(int i=1;i<=n;i++){
	    cin>>a[i];
	    put(a[i]);
	}
}
int get(){
	int res=heap[1];
	heap[1]=heap[size--];
	int now=1,nxt;
	while(now*2<=size){
		nxt=now<<1;
		if(nxt<size && heap[nxt+1]<heap[nxt]) nxt++;
		if(heap[nxt]>=heap[now]) return res;
		heap[now]^=heap[nxt]^=heap[now]^=heap[nxt];
		now=nxt;
	}
	return res;
}
int work(){
	int x,y;
	for(int i=1;i<n;i++){
		x=get();
		y=get();
		ans+=x+y;
		put(x+y);
	}
	return ans;
}
int main(){
	init();
	cout<<work();
	return 0;
}

algorithm库的堆成员函数:

#include<bits/stdc++.h>
using namespace std;
const int N=10000+5;
int heap[N],a[N],x,y,size,n,ans;
void put(int d){
	heap[++size]=d;
	push_heap(heap+1,heap+size+1,greater<int>());
}
int get(){
	pop_heap(heap+1,heap+size+1,greater<int>());
	return heap[size--];
}
int work(){
	cin>>n;
	for(int i=1;i<=n;i++){
	    cin>>a[i];
	    put(a[i]);
	}
	for(int i=1;i<n;i++){
		x=get();
		y=get();
		ans+=x+y;
		put(x+y);
	}
	cout<<ans;
}
int main(){
	work(); 
	return 0;
}
两种写法都是AC,但个人认为利弊都有, 如果只是单纯的维护堆,可以直接用algorithm;但在堆中要维护其他值,手写堆会好一些如果可以用algo维护其他的值,请大佬们指教(抱拳));

要上分推了,先溜了~嘻嘻

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值