7-8 修理牧场(25 分)
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
思路:
堆排序的简单应用。之前不懂优先队列,写的代码都是超时的。。。。。
如果看不懂的话,去找找优先队列的实现代码来看看吧。 我是看啊哈磊的。(所以有些地方和细节基本一样)
代码:
#include
int N,tree[10003],sum = 0;
using namespace std;
void Swap_num(int x, int y)
{
int num = tree[x];
tree[x]= tree[y];
tree[y] = num;
//Swap_num(tree[x],tree[y]);
return ;
}
void SiftDown(int i)// 向下调整函数, i即为开始向下调整的树根
{
int min_num, flag = 0;
while (i*2 <= N )
{
if( tree[i] > tree[ i * 2])
min_num = i* 2;
else min_num = i;
if((i*2 + 1) <= N && tree[i*2 + 1] < tree[min_num])
min_num = i *2 +1;
if( i == min_num ) break;
else
{
Swap_num(i, min_num);
i = min_num;
}
}
return ;
}
int DeleteTop()
{
int top = tree[1];
tree[1] = tree[N];
N--;
SiftDown(1);
return top;
}
void CreatTree()
{
scanf("%d",&N);
for(int i = 1; i <= N;++i)
{
scanf("%d",&tree[i]);
}
for(int i = N/2; i >=1 ; --i)
SiftDown(i);
return ;
}
void SiftUp(int i)
{
if( i == 1 ) return ;
while(i != 1)
{
if(tree[i] < tree[i/2])
Swap_num(i, i/2);
else break;
i = i/2;
}
return ;
}
void Insert (int num)
{
N++;
tree[N] = num;
SiftUp(N);
return ;
}
int Solve()
{
int ans = 0;
while( N > 1)
{
int min_two = 0;
min_two +=DeleteTop();
min_two +=DeleteTop();
Insert(min_two);
ans += min_two;
}
return ans;
}
int main()
{
CreatTree();
printf("%d",Solve());
return 0;
}