这道题的做法有很多种,嘻嘻
1、贪心(好像几个月前就这样AC的)
排序是必须的,(我们不可能盲目的合并任意两堆石子)因为按照最小石子合并得到的最后答案一定是最小的;可以考虑用两个数组来分别存放合并了的石子堆和未合并的石子堆(b[ ]和a[ ]);
然后我们比较当前没有合并的石子堆中的前两个和合并了的石子堆中的一个,比较合并哪两个石子堆会得到最小值;
代码如下:
#include
using namespace std;
bool cmp(const int &a,const int &b){
return a>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]m || j<=m && i<=n && a[i]
2、优先队列
也是排序的思路,但是这里利用了优先队列的性质,不论元素在队列中的那个位置,即使是在队尾,如果他优先级最高,要他出队也得出队。所以我们只需要每次都出两个元素,并将这两个元素合并的一个新石子堆的值跳到队中,就完成了一次合并;
由于n堆石子要合并n-1次才能剩下最后一堆,所以循环次数为n-1;
代码如下:
#include
#include
#include
using namespace std;
priority_queue< int , vector , greater > 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
3、堆
这里用的是小根堆,还是利用了数据结构的性质——最小的最先出,思路和优先队列差不多(取堆+取堆+存堆);
若要了解小(大)根堆,点击:http://blog.csdn.net/pngynghay/article/details/22052737
代码如下:
手写堆:
#include
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=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
algorithm库的堆成员函数:
#include
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 get(){
pop_heap(heap+1,heap+size+1,greater());
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
两种写法都是AC,但个人认为利弊都有,
如果只是单纯的维护堆,可以直接用algorithm;但在堆中要维护其他值,手写堆会好一些(
如果可以用algo维护其他的值,请大佬们指教(抱拳));
要上分推了,先溜了~嘻嘻