修理牧场 (25 分)

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L​i​​个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L​i​​的总和。

但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

输入格式:

输入首先给出正整数N(≤10​4​​),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。

输出格式:

输出一个整数,即将木头锯成N块的最少花费。

输入样例:

8
4 5 1 2 1 3 1 1

输出样例:

49

首先想的做法:

#include<bits/stdc++.h>
using namespace std;

#define N 10010
// 哈夫曼树的结点结构
struct element
{
    int weight;        // 权值域
    int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
};
// 选取权值最小的两个结点
void selectMin(element a[],int n, int &s1, int &s2)
{
    for (int i = 0; i < n; i++)
    {
        if (a[i].parent == -1)// 初始化s1,s1的双亲为-1
        {
            s1 = i;
            break;
        }
    }
    for (int i = 0; i < n; i++)// s1为权值最小的下标
    {
        if (a[i].parent == -1 && a[s1].weight > a[i].weight)
            s1 = i;
    }
    for (int j = 0; j < n; j++)
    {
        if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的双亲为-1
        {
            s2 = j;
            break;
        }
    }
    for (int j = 0; j < n; j++)// s2为另一个权值最小的结点
    {
        if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
            s2 = j;
    }
}
// 哈夫曼算法
// n个叶子结点的权值保存在数组w中
void HuffmanTree(element huftree[], int w[], int n)
{
    int sum=0;
    for (int i = 0; i < 2*n-1; i++)    // 初始化,所有结点均没有双亲和孩子
    {
        huftree[i].parent = -1;
        huftree[i].lchild = -1;
        huftree[i].rchild = -1;
    }
    for (int i = 0; i < n; i++)    // 构造只有根节点的n棵二叉树
    {
        huftree[i].weight = w[i];
    }
    for (int k = n; k < 2 * n - 1; k++) // n-1次合并
    {
        int i1, i2;
        selectMin(huftree, k, i1, i2); // 查找权值最小的俩个根节点,下标为i1,i2
        // 将i1,i2合并,且i1和i2的双亲为k
        huftree[i1].parent = k;
        huftree[i2].parent = k;
        huftree[k].lchild = i1;
        huftree[k].rchild = i2;
        huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
    }
    for(int i=n;i<2*n-1;i++)
    {
        sum+= huftree[i].weight;
    }
    printf("%d",sum);
}

int main()
{
    int x[N],n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>x[i];
    }
    element *hufftree=new element[2*n-1];    // 动态创建数组
    HuffmanTree(hufftree, x, n);
    return 0;
}

 发现会超时……上网查了查其他人的做法,发现大部分人是用优先队列模拟哈夫曼树

#include <bits/stdc++.h>
using namespace std;
int main(){
    priority_queue<int,vector<int>,greater<int> >l;
    int n,a;
    cin>>n;
    for (int i=0;i<n;i++){
        cin>>a;
        l.push(a);
    }
    int sum=0;
    while(l.size()!=1){
        int x=l.top();
        l.pop();
        int y=l.top();
        l.pop();
        sum+=x+y;
        l.push(x+y);
    }
    printf("%d\n",sum);
    return 0;
}

优先队列:https://www.cnblogs.com/xzxl/p/7266404.html 转载自GGBeng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值