博主与合并果子斗争许久了,最初接触到的便是贪心。
于是就有如下双队列的方法。
#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;
}