2-5 修理牧场 (35分) 哈夫曼树例题 c与c++鸳鸯解法 详细解释

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

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

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

输入格式:

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

输出格式:

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

输入样例:

8
4 5 1 2 1 3 1 1

输出样例:

49

思路

构造最优二叉树,将除叶节点外所有的节点权值加和。即为所求。

实际上是没必要构造一颗树的,运用他的原理即可

其实这两个解法差不多,但是c++更加的简单易于理解,在时间上也是很短的。c相对而言就比较暴力了。相当于对c++解法的底层解释。注重基础。

c++解法

#include<stdio.h>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > Q;
int main(){
    int x,n,sum = 0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&x);
        Q.push(x);
    }
    while(Q.size()>1){
        int a=Q.top();
        Q.pop();
        int b=Q.top();
        Q.pop();
        Q.push(a+b);
        sum+=a+b;
    }
    printf("%d",sum);
    return 0;
}

在这里解释一下这句话

priority_queue<int,vector<int>,greater<int> > Q;

priority_queue<Type, Container, Functional>,其中Type 为数据类型,Container为保存数据的容器,Functional 为元素比较方式。
Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。
greater 可以实现由底部到顶部大到小实现。
所以这道题的步骤就是,
push出两个最小值并相加,将相加的值加到sum并放回Q中,然后会重新排列大小。
以此类推

在这里插入图片描述
不仅代码量很少,时间也是很短的,考试的时候可以使用,平时练习不建议,有点投机取巧。练习还是用c一步步实现他的每一个步骤。

c解法

用c语言其实就是对c++的具体实现,(可能我这个不是最好的解法。)但是每次取每次放都需要重新排序,这将是一件很累的事情。所以干脆就不排序了,直接放在那,取的时候再去判断最小值。

#include <stdio.h>
int a[10010],n;
#define Max 10000000
int findMin(){
    int min = Max+1,i;
    for (i = 0; i<n; i++)
        if (min>a[i]) min = a[i];
    return min;
}
void Delete(int x){
    int i;
    for (i = 0; i<n; i++)
        if (a[i] == x) {
            a[i] = Max;
            return;
        }
}
void add(int x){
    int i;
    for (i = 0; i<n; i++)
        if (a[i] == Max) {
            a[i] = x;
            return;
        }
}
int main(){
    int i,sum2 = 0;
    scanf("%d",&n);
    for (i = 0; i<n; i++)
        scanf("%d",&a[i]);
    for (i = 1; i<n; i++) {
        int x = findMin();
        Delete(x);
        int y = findMin();
        Delete(y);
        add(x+y);
        sum2+=x+y;
    }
    printf("%d\n",sum2);
}

这里注明一下:删除其实就是把现在这个数组里这个值(不一定是之前取的那个数)给赋值为非常大,这样下次寻找最小值就不会找到他。
如果有添加,那么之前一定有删除,直接把添加的值放在删除的值的地方就行了。
Max一定要特别大,要不然,最大值测试用例时,x+y的值甚至会大过Max,这样就出错了。
这个实现就很耗时了,算是锻炼思维把。
在这里插入图片描述

如果有更好的解法,或者是有什么问题的话,欢迎留言。

发布了11 篇原创文章 · 获赞 9 · 访问量 543

猜你喜欢

转载自blog.csdn.net/VistorsYan/article/details/103437448