农夫约翰想修理牧场周围的一小段围栏。他测量围栏并认定他需要Ñ(1≤ Ñ ≤20000)厚木板,每一个都具有一些整数长度大号我(1≤ 大号我 ≤50000)单元。然后,他购买一块长板足够长,以便看到N块板(即,其长度是长度L i的总和)。FJ忽略了“切口”,锯齿切割时锯屑的额外长度; 你也应该忽略它。
FJ悲伤地意识到,他没有一把砍伐木头的锯子,所以他用这张长板子将农民交给了Farmer Don's Farm,并礼貌地问他是否可以借用一把锯子。
一个衣柜资本家农夫唐(Donmer Don)并不是向FJ借一把锯子,而是向该农民约翰收取木板上N-1个切口的费用。砍一块木头的费用与其长度完全相等。切割长度为21的木板需要21美分。
农夫唐然后让农夫约翰决定顺序和地点切割木板。帮助Farmer John确定他可以用来创建N木板的最小金额。FJ知道他可以用各种不同的顺序切割板子,这将导致不同的收费,因为所产生的中间板条具有不同的长度。
输入
第1行:一个整数
N
,木板数量
第2行..
N
+ 1:每行包含一个描述所需木板长度的整数
产量
第1行:一个整数:他必须花费最少的金钱来制作
N
-1个剪辑
示例输入
3
8
5
8
示例输出
34
暗示
他希望将长度为21的棋盘切成长度为8,5和8的棋子。
原来棋盘上的棋子为 8 + 5 + 8 = 21。第一次切割将花费21美元,并且应该用于将板切割成13和8片。第二次切割将花费13,并且应该用于将13切割成8和5.这将花费21 + 13 = 34 。如果21被切割成16和5,则第二次切割将花费16次,总共37次(大于34次)。
思路分析:
这道题是我初试优先队列的题,所以一定要拿个小本子记下来。
这道题的思路其实挺简单的,就是每次找两个最小的数求和,并将他们两数的和弹入队列即可,直到队列中只剩下最后一个元素即可。
此处主要代码为:
while(q.size()!=1)
{
ll a=q.top();
q.pop();
ll b=q.top();
b=q.top();
q.pop();
ll c=a+b;
ans+=c;
q.push(c);
}
文末最后提一下优先队列:
priority_queue<long long ,vector<long long> ,greater<long long> >;这个是单增的队列
priority_queue<long long ,vector<long long> ,less<long long> >;这个是单减的队列
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<limits>
#include<queue>
using namespace std;
typedef long long ll;
int N;
ll l[20005];
ll ans;
priority_queue<ll ,vector<ll>,greater<ll> >q;
int main()
{
while(scanf("%d%*c",&N)!=EOF)
{
ans=0;
while(!q.empty())
{
q.pop();
}
for(int i=0;i<N;i++)
{
scanf("%lld%*c",&l[i]);
q.push(l[i]);
}
while(q.size()!=1)
{
ll a=q.top();
q.pop();
ll b=q.top();
b=q.top();
q.pop();
ll c=a+b;
ans+=c;
q.push(c);
}
printf("%lld\n",ans);
}
return 0;
}