贪心策略解决木板截取最小开销问题------类哈夫曼编码问题

贪心策略解决木板截取最小开销问题------类哈夫曼编码问题

一、贪心法:遵循某种规则,不断贪心的选择当前最优策略的算法设计方法。常见问题有:最少硬币问题、区间问题、字典序最小问题、点覆盖问题、木板截取问题等。

二、木板截取问题

三、算法分析与设计

由于已经给出了截取后得到的每块木板的长度,要让总开销最小,那么我们按照贪心的思想让每次截取开销最小即可,

因此我每次选择最小的两截木板作为被截开木板,因此我们不难发现这其实是一个变形的哈夫曼编码问题。

        /// <summary>
        /// 贪心策略解决木板截取最小开销问题,类哈夫曼编码问题
        /// </summary>
        /// <param name="n"></param>
        /// <param name="everyChildBoardLen"></param>
        /// <returns></returns>
        public int CaluateMinSpendInCutBoard(int n,int[] everyChildBoardLen)
        {
            int spends = 0;
            int maxSpends = 0;
            foreach (int i in everyChildBoardLen)
            {
                maxSpends += i;
            }

            while (true)
            {
                //获取数组中最小的两个木板的下标
                GetMinNumAndSecondMinNumIndex(everyChildBoardLen,out int minNumIndex,out int secondMinNumIndex);
                //计算这两个木板的开销
                int tempSpends=everyChildBoardLen[minNumIndex] + everyChildBoardLen[secondMinNumIndex];
                //将开销加入到总开销中
                spends += tempSpends;
                everyChildBoardLen[minNumIndex] = tempSpends;
                //这里将已经遍历过的其中一个数标记成-1(达到删除的状态)
                everyChildBoardLen[secondMinNumIndex] = int.MaxValue;
                if (tempSpends == maxSpends)
                    break;
            }
            return spends;
        }
        /// <summary>
        /// 获取数组最小和次小的数据(至少有两个数)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="minNum"></param>
        /// <param name="secondMinNum"></param>
        public void GetMinNumAndSecondMinNumIndex(int[] a,out int minNumIndex,out int secondMinNumIndex)
        {
            minNumIndex = a[0]>a[1]?1:0;
            secondMinNumIndex = a[0] > a[1] ? 0 : 1;

            for (int i=2;i<a.Length;i++)
            {
                if (a[i]!=int.MaxValue)
                {
                    if (a[i] < a[minNumIndex])
                    {
                        secondMinNumIndex = minNumIndex;
                        minNumIndex = i;
                    }
                    else if(a[i]<a[secondMinNumIndex])
                    {
                        secondMinNumIndex = i;
                    }
                    
                }
            }
            
        }

本算法中需要每次去获取木板数组中最短和次短的模板,因此涉及到高效获取最短和次短的模板的问题,我们可以采用先从小到大排序数组,然后取出前两个数即可,但是排序最快的快速排序的复杂度是nlogn,似乎有点不太理想。

那么如何不依赖排序来实现获取最小和次小的问题,我们可以按照GetMinNumAndSecondMinNumIndex方法的思想来实现复杂度为O(n)算法。其基本思路如下:

设置两个存储变量minNum和secondMinNum,初始值为数组下边为0,1中最小和最大的,然后进行遍历,当发现某个数小于当前最小值,则原有最小值赋值给secondMinNum,赋值minNum为更小的值,否则将当前数和secondMinNum比较,如果小于secondMinNum,则给secondMinNum赋值当前值,一直到遍历结束。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浪舟子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值