[题解] 合并果子 三种方法

博主与合并果子斗争许久了,最初接触到的便是贪心。

于是就有如下双队列的方法。

#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define re return
#define s(a)  sizeof(a) 
#define maxx(a,b,c) max(max(a,b),c)
#define minx(a,b,c) min(min(a,b),c)
#define up(i,m,n) for(int i=m;i<=n;i++)
#define down(i,m,n) for(int i=n;i>=m;i--)
using namespace std; 
const int MAXN=30005;
int a[MAXN],b[MAXN],n;
inline int init()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
      	scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    memset(b,67,s(b));
}
inline int solve()
{
	int h1=0,t1=n,h2=0,t2=0;
	int ans=0;
	while (t1-h1+t2-h2>1)
    { 
      int temp=0;
      if (h1==t1||h2<t2&&b[h2+1]<a[h1+1])//first
        temp+=b[++h2];
      else 
        temp+=a[++h1];
      if (h1==t1||h2<t2&&b[h2+1]<a[h1+1])//second
        temp+=b[++h2];
      else 
        temp+=a[++h1];
      ans+=temp;
      b[++t2]=temp;    
    }
     return ans;
}
int main()
{
    init();
    cout<<solve()<<endl;
    return 0;
}

之后又学了堆(heap)

于是便有一个感觉,堆就是为合并果子而生的啊!

以下是手打堆,

注意堆的get( )与put( );

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime>
#define re return
#define LL long long
#define s(a) sizeof(a)
#define clr(a,x) memset(x,a,s(x))
#define mint(a,b,c) min(min(a,b),c)
#define maxt(a,b,c) max(max(a,b),c)
#define up(i,m,n) for (int i=m;i<=n;i++)
#define down(i,m,n) for (int i=n;i>=m;i--)
using namespace std;
const int MAXN=100005;
int heap[MAXN];
int len=0,n=0;
void put(int x)
{
	int pos,ne;
	heap[++len]=x;
	pos=len;
	while(pos>1)
	{
		ne=pos>>1;
		if (heap[pos]>=heap[ne])return;
		swap(heap[pos],heap[ne]);
		pos=ne;
	}	
}
int get()
{
	int pos,ans=0,ne;
	ans=heap[1];
	heap[1]=heap[len--];
	pos=1;
	while(pos*2<=len)
	{
		ne=pos*2;
		if(ne<len&&heap[ne+1]<heap[ne]) ne++;
		if (heap[pos]<=heap[ne]) return ans;
		swap(heap[pos],heap[ne]);
		pos=ne;
	}
	return ans;
}
int solve()
{
	int tot=0;int a;
	up(i,1,n)
	  cin>>a,put(a);
	up(i,1,n-1)
	{
		int x;
		x=get();
		int y;
		y=get();
		tot+=x+y;
		put(x+y);
	}
	re tot;
}
int main()
{
	freopen("fruit.in","r",stdin);
	freopen("fruit.out","w",stdout);
	cin>>n;
	cout<<solve()<<endl;
	re 0;
}
然而 C++的STL提供了一个牛B的东西,优先队列

priority_queue< int,vector<int>,greater<int> > h;
这是一个优先队列h,(greater<int>)  表示小根堆,即跟为最小值;

若要求大根堆,则不加greater<int>;

代码如下

#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define re return
#define s(a)  sizeof(a) 
#define maxx(a,b,c) max(max(a,b),c)
#define minx(a,b,c) min(min(a,b),c)
#define up(i,m,n) for(int i=m;i<=n;i++)
#define down(i,m,n) for(int i=n;i>=m;i--)
using namespace std; 
const int MAXN=30005;
priority_queue< int,vector<int>,greater<int> > h;//优先队列; 
int main()
{
	int n,t;
	ios::sync_with_stdio(false);
	cin>>n;
	up(i,1,n)
	  cin>>t,h.push(t);
	int ans=0;
	up(i,1,n-1)
	{
		int x,y;
		x=h.top();h.pop();
		y=h.top();h.pop();
		ans+=x+y;
		h.push(x+y);
	}
	cout<<ans<<endl;
	re 0;
}

非常强大;

但是,但是,博主昨晚睡觉是YY出了很强的方法,有受堆的思想的影响;

若每次都是取最小的一个,为什么不把最小的放在队尾,每次去最后一个,放入时用一个sort不就好了么

于是

#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define re return
#define clr(a,b) memset(b,a,s(a))
#define s(a)  sizeof(a) 
#define maxx(a,b,c) max(max(a,b),c)
#define minx(a,b,c) min(min(a,b),c)
#define up(i,m,n) for(int i=m;i<=n;i++)
#define down(i,m,n) for(int i=n;i>=m;i--)
using namespace std;
const int MAXN=30005;
int f[MAXN],n;
bool cmp(const int &a,const int &b)
{
	return a>b;
}
void init()
{
	scanf("%d",&n);
	up(i,1,n)
	  scanf("%d",f+i);
	sort(f+1,f+1+n,cmp);
}
int make()
{
	return f[--n+1];
}
int push(int x)
{
	f[++n]=x;
	sort(f+1,f+1+n,cmp);
}
int main()
{
	freopen("fruit.in","r",stdin);
	freopen("fruit.out","w",stdout);
	ios::sync_with_stdio(false);
	int ans=0;
	init();
	int len=n;
	up(i,1,len-1)
	  {
	  	 int x=make();
	  	 int t=make();
	  	 push(x+t);
	  	 ans+=x+t;
	  }
	cout<<ans<<endl;
	re 0;
}

果断超时,最慢的12.9s;

汗!!!

于是改进,

时间复杂度骤降(log n (不知是否算错)),大家注重理解;(有读入优化可以copy走)

#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define re return
#define s(a)  sizeof(a) 
#define maxx(a,b,c) max(max(a,b),c)
#define minx(a,b,c) min(min(a,b),c)
#define up(i,m,n) for(int i=m;i<=n;i++)
#define down(i,m,n) for(int i=n;i>=m;i--)
using namespace std; 
const int MAXN=30005;
int f[MAXN],n;  
template <class T>
inline int read(T &x)
{
	x = 0;
	T flag = 1;
	char ch = (char)getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = (char)getchar();
	}
	while(ch>='0' && ch<='9')
	{
		x = (x<<1) + (x<<3) + ch - '0';
		ch = (char)getchar();
	}
	x *= flag;
	return 1;
}
int make(int x)  
{  
    int t;
    t=x;  
    for(int i=t+1;i<=n;i++)   
        if(f[i]<f[t])  
            t=i;  
    swap(f[x],f[t]);  
}  
int main()  
{  
        freopen("fruit.in","r",stdin);
        freopen("fruit.out","w",stdout);
        int i,sum;  
        read(n);
        sum=0;  
        for(i=1;i<=n;i++)  
            read(f[i]);   
        for(i=1;i<=n-1;i++)  
        {   
		    make(i);  
            make(i+1);
            f[i+1]+=f[i];
            sum+=f[i+1];  
        }  
        printf("%d\n",sum);   
        return 0;
}  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值