这道题总的思想就是贪心,因为每修一次的花费就是修的板的总长度,每次修就是将两块板合为一块板,所以总共要修n-1次。修的次数是一定的,所以要使总花费最小的话,只要每次修最短的两块板就行了,因此在求的过程中要时时更新和维护最小的两块板。有些同学直接想到用数组存各个板的长度,然后sort一下,之后每合成一块板就插入一下,再修改一下下标。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1000001;
int n,a[maxn],i,j,k,b;
long long sum,ans=0;
int main()
{
scanf("%d",&n);
int l=n;
for(i=1;i<=n;++i)scanf("%d",&a[i]);
sort(a+1,a+n+1);
k=1;
for(i=1;i<n;++i)
{
sum=a[k]+a[k+1];
ans+=sum;
k+=2;
b=k;
while(a[k]<sum&&k<=l)k++;
for(j=l+1;j>k;--j)a[j]=a[j-1];
a[k]=sum;
l++;
k=b;
}
printf("%lld\n",ans);
}
这显然可以,但还有更简易的方法,有一种数据结构叫做——priority_queue(优先队列)。
想到用优先队列做这道题就基本结束了,之后只是代码的实现了,每次合成时抽出队列前两个元素,合成完再push进去,但要注意要定义成小顶堆。下面给出代码。
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define M 100005
#define ll long long
using namespace std;
int main(){
int n;
ll ans=0,x;
priority_queue<ll,vector<ll>,greater<ll> >q;
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>x;
q.push(x);
}
while(q.size()>1){
ll x1=q.top();q.pop();
ll x2=q.top();q.pop();
ll sum=x1+x2;
ans=ans+sum;
q.push(sum);
}
cout<<ans<<endl;
return 0;
}
当解题时需要维护一下变量时,可以考虑采用适当的数据结构,这道题就是一个典型的例子。
Algorithm+Data Structures=Programs
——Niklaus Wirth