7-8 修理牧场(25 分)

2 篇文章 0 订阅
1 篇文章 0 订阅
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块的最少花费。

输入格式:

输入首先给出正整数N104),表示要将木头锯成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;
}

    
    

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值