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

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

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

二、木板截取问题

贪心策略解决木板截取最小开销问题------类哈夫曼编码问题_第1张图片

三、算法分析与设计

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

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

贪心策略解决木板截取最小开销问题------类哈夫曼编码问题_第2张图片

        /// 
        /// 贪心策略解决木板截取最小开销问题,类哈夫曼编码问题
        /// 
        /// 
        /// 
        /// 
        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;
        }
        /// 
        /// 获取数组最小和次小的数据(至少有两个数)
        /// 
        /// 
        /// 
        /// 
        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赋值当前值,一直到遍历结束。

你可能感兴趣的:(算法,算法,贪心策略,哈夫曼编码,模板截取最小开支)