1. 程式人生 > >【51Nod - 1117】【聰明的木匠 】

【51Nod - 1117】【聰明的木匠 】

題目:
 

一位老木匠需要將一根長的木棒切成N段。每段的長度分別為L1,L2,......,LN(1 <= L1,L2,…,LN <= 1000,且均為整數)個長度單位。我們認為切割時僅在整數點處切且沒有木材損失。

木匠發現,每一次切割花費的體力與該木棒的長度成正比,不妨設切割長度為1的木棒花費1單位體力。例如:若N=3,L1 = 3,L2 = 4,L3 = 5,則木棒原長為12,木匠可以有多種切法,如:先將12切成3+9.,花費12體力,再將9切成4+5,花費9體力,一共花費21體力;還可以先將12切成4+8,花費12體力,再將8切成3+5,花費8體力,一共花費20體力。顯然,後者比前者更省體力。

那麼,木匠至少要花費多少體力才能完成切割任務呢?

Input

第1行:1個整數N(2 <= N <= 50000) 
第2 - N + 1行:每行1個整數Li(1 <= Li <= 1000)。

Output

輸出最小的體力消耗。

Sample Input

3
3
4
5

Sample Output

19

解題報告:貪心的題目,一想就知道要每次先把最長的截斷,然後自己就傻傻的按照他給的段長排序,入坑了,其實思考到了這是個可以從小段向長進展的,一個逆推的過程,自己忽略一點就是小段之和 可能會大於之後的段長,那麼之前的排序就是不合理的了。所以說正解就是優先佇列,自己需要每次更新,將其中最小的兩個踢出去,將二者的和壓進去。

ac程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=50008;
ll num[maxn];
ll sum[maxn];
priority_queue<ll,vector<ll> ,greater<ll> > q;
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		while(q.size()) q.pop();
		for(int i=0;i<n;i++)
		{
			cin>>num[i];
			q.push(num[i]);	
		}
		ll ans=0;
		while(q.size()>1)
		{
			ll a,b;
			a=q.top();
			q.pop();
			b=q.top();
			q.pop();
			ans+=(a+b);
			q.push(a+b);
		}
		printf("%lld\n",ans);
	}
	
}