R7-3 修理牧场

R7-3 修理牧场
分数 20
作者 DS课程组
单位 浙江大学
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

R7-3 修理牧场 解题分项
(前提说明:本人菜菜,如有帮助那不胜荣幸,觉得屎山正常,有更好的解题思路感谢)
本题应该用哈弗曼树去解,原因有以下几点:
1.其数据形式适合用树去存储,符合其存储形态;
2.其要求求解得是非叶子结点的最小和,适合用其算法解决;

如何实现哈夫曼树?
最开始的时候想用数组去保存叶结点,然后用树去描述关系,后来想想太麻烦,费脑子,于是就准备直接用数组去存,然后把所有的非叶给加起来。
根据哈夫曼树的算法,首先应该将最小的两个数和成一个树,根节点为两者的和,再用这两者的和加入数组继续比较,且因为我们要求的是非叶子节点的总和,所以每次获得非叶子结点就可以给他加进要求的数里。
其逻辑归纳为{排序->找到最小的两个数->获得其根节点也即为两个的数的和->将两个数的和加入所有非叶子结点数和->将两个数的和插入数组里->重复1,直到最后一个数。
具体实现中,为了保证其整体的有序性,所以准备在插入的时候便让它有序插入,为了保证速度写了二分法插入。
也因为插入所以会导致其实际队伍越来越长,其不断的向后扩展,导致其空间占用高,这应该也可以优化。
不说了下一道题。

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



//冒泡排序算法
void MPsort(int eve[],int cout)
{
    int a;
    for(int i=0; i<cout-1; i++)
    {
        for(int i1=0; i1<cout-1; i1++)
        {
            if(eve[i1]>eve[i1+1])
            {
                a=eve[i1];
                eve[i1]=eve[i1+1];
                eve[i1+1]=a;
            }

        }

    }

}

int EFFind(int mid,int left,int right,int *eve,int sum){
        int numberins;
 if(sum<=eve[left]){
        numberins=left;
      }
     else if(sum>=eve[right]){
        numberins=right+1;
      }
       else{while(1){
            mid=(left+right)/2;

            if(sum>=eve[mid]&&sum<=eve[mid+1]){
                numberins=mid+1;
                break;
            }
            else if(sum<=eve[mid]&&sum>=eve[mid-1]){
                numberins=mid;
                break;
            }
            else if(sum==eve[mid]){
                numberins=mid;
                break;
            }
            else if(sum>eve[mid]){
                left=mid+1;
            }
            else if(sum<eve[mid]){
                right=mid-1;
            }


        }}

        return numberins;//类似二分查找的找插入点
}


int main()
{
    int cout;
    scanf("%d",&cout);//存储一共切成几块;
    int eve[20001];//建立一个数组用来存储每块木块的长度;

    for(int i=0; i<cout; i++)
    {
        scanf("%d",&eve[i]);//存储切成块的长度
    }
    //这个题应该是用哈夫曼树来解决,因为其很符合哈夫曼树的特性与形态结构,所以先写个哈夫曼树。
    //哈夫曼树要先挑最小的。
    //对于树的存储结构我决定用数组去存储,比较直观,而且方便运算。
    //感觉用树存储很麻烦,不如直接用数组去解决。
    //排序采用最简单的冒泡排序;其实感觉排序的数组用链表存储更好?因为方便插入,后面查找写个二分的话算法效率会更快?
    //数组的话插入麻烦。数组写起来简单,看看能不能过。
    MPsort(eve,cout);
    //✖排序后进入建树阶段,虽然是用数组存储,但是其不是完全二叉树,所以为了让其更好理解便在结构体上加上了辅助的指代;
    //✔后来决定不建树了,建树后其描述树的关系太过复杂,倒不如直接用数组去做。哈夫曼树不一定要写树的数据结构,重点在于其思想。
    //如何实现哈夫曼树呢?
    /*首先要挑出两个最小的拿出来构成一个树,根节点为两个的和。
      然后需要对他的和进行排序放到数组里。
      然后不断运行,直到构建到最后一个数。
      最后我们要求的是所有根节点的和。
    */
    //所以由于3先保证复用性;
    int sum=0;//根节点
    int all_sum=0;//所有根节点的和
    int left=0;//二分的左右
    int right=0;
    int numberins,mid=0;

    for(int i=0;i<cout-1;i=i+2){//因为后边+1了,所以截止到cout-1
        sum=eve[i]+eve[i+1];//sum为根节点的值,左右为eve[I]与i+1;
        all_sum=all_sum+sum;//所求值
        //然后对其sum放到数组里,也就是执行一个数组的插入,而且这个数组还是有序的,那就二分;
        //二分是i+2到cout,这里需要找到一个sum的最小区间
        left=i+2;
        right=cout-1;
        //这个和二分查找的不同点在于,二分找不到就算了,这个找不到头就加头上或者尾上。
        //但这个有个缺点,就是其占用的空间很大,因为我的数组不断的向后伸长而不是重写,后面不行的话再优化;
        numberins=EFFind(mid,left,right,eve,sum);
        //因为这个东西调试了整整一天,难蚌。原因有两个,一个是不熟练,另一个是没找好道路。
        cout++;
        if(numberins<right){
        for(int g=cout;g>numberins;g--){
            eve[g]=eve[g-1];
        }}
        eve[numberins]=sum;
    }

    printf("%d",all_sum);


}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jrenc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值