动态规划-钢条切割问题

1.动态规划

         什么是动态规划,我们要如何描述它?
        动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。

        动态规划和分治法相似,都是通过组合子问题的解来求解原问题。分治法将问题划分成互不相交的子问题,递归求解子问题,再将他们的解组合起来,求出原问题的解。与之相反,动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子子问题。在这种情况下,分治算法会做出许多不必要的工作,它会反复的求解那些公共子问题。而动态规划算法对每个子子问题只求解一次,将结果保存到表格中,从而无需每次求解一个子子问题都要重新计算。

2.动态规划-钢条切割问题

        假定我们知道sering公司出售一段长度为I英寸的钢条的价格为pi(i=1,2,3….)钢条长度为整英寸如图给出价格表的描述(任意长度的钢条价格都有)

先给我们一段长度为 n 的钢条,问怎么切割,获得的收益最大 r n ?

考虑n=4的时候

扫描二维码关注公众号,回复: 913441 查看本文章

假如一个最优解把n段七个成了k段(1<=k<=n,那么最优切割方案:

最大收益:


第一种求最优解方案:

对于r n (n>=1),最优切割收益:

 

将切割方案分成下面几种
1 ,不切割  收益为 p n
2 ,将它切割成两半,切割成两半的情况有,对每种情况求最优解
  (1,n-1) (2,n-2) (3,n-3) (4,n-4) ..... (n-1,1)
   对这两半分别求最优解 , 最优解的和就是当前情况的最优解
第二种求最优解方案:

我们从钢条的左边切下长度为i的一段,只对右边剩下长度为n-i的一段继续进行切割,对左边的不再切割。这样,不做任何切割的方案就是:当第一段长度为n的时候,收益为pn,剩余长度为0,对应的收益为0。如果第一段长度为i,收益为pi

代码实现 - 自顶向下递归实现
分析效率,关于上述方法的运行性能时间问题。
动态规划的方法进行求解
上面的方法之所以效率很低,是因为它反复求解相同的子问题。因此,动态规划算法安排求解的顺序,对每个子问题只求解一次,并将结果保存下来。如果随后再次需要此子问题的解,只需查找保存的结果,不必重新计算。因此动态规划的方法是付出额外的内存空间来节省计算时间。
动态规划有两种等价的实现方法(我们使用上面的钢条切割问题为例,实现这两种方法)
第一种方法是带备忘的自顶向下法
   此方法依然是按照自然的递归形式编写过程,但过程中会保存每个子问题的解(通常保存在一个数组中)。当需要计算一个子问题的解时,过程首先检查是否已经保存过此解。如果是,则直接返回保存的值,从而节省了计算时间;如果没有保存过此解,按照正常方式计算这个子问题。我们称这个递归过程是带备忘的。
第二种方法是自底向上法

  首先恰当的定义子问题的规模,使得任何问题的求解都只依赖于更小的子问题的解。因而我们将子问题按照规模排序,按从小到大的顺序求解。当求解某个问题的时候,它所依赖的更小的子问题都已经求解完毕,结果已经保存。

3.代码实现

3.1递归实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _506_钢条切割问题_递归实现
{
    class Program
    {
        static void Main(string[] args)
        {
            int n = 5;//要切割钢条的长度
            int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表,索引值代表钢条长度,值代表价格
            Console.WriteLine(UpDown(0,p));
            Console.WriteLine(UpDown(1, p));
            Console.WriteLine(UpDown(2, p));
            Console.WriteLine(UpDown(3, p));
            Console.WriteLine(UpDown(4, p));
            Console.WriteLine(UpDown(5, p));
            Console.WriteLine(UpDown(6, p));
            Console.WriteLine(UpDown(7, p));
            Console.WriteLine(UpDown(8, p));
            Console.WriteLine(UpDown(9, p));
            Console.WriteLine(UpDown(10, p));

            Console.ReadKey();
        }
        private static int UpDown(int n,int[] p)
        {
            if (n == 0) return 0;
            int tempMaxPrice = 0;
            for(int i=1;i<=n;i++)
            {
                int maxPrice = p[i] + UpDown(n - i, p);
                if(maxPrice>tempMaxPrice)
                {
                    tempMaxPrice = maxPrice;
                }
            }
            return tempMaxPrice;
        }
    }
}

3.2 带备忘录的自顶向下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _507_钢条切割_带备忘的自顶向下_动态规划_
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] resultPrice = new int[11];//储存计算过的钢条切割后价格

            int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表,索引值代表钢条长度,值代表价格
            Console.WriteLine(UpDown(0, p,resultPrice));
            Console.WriteLine(UpDown(1, p, resultPrice));
            Console.WriteLine(UpDown(2, p, resultPrice));
            Console.WriteLine(UpDown(3, p, resultPrice));
            Console.WriteLine(UpDown(4, p, resultPrice));
            Console.WriteLine(UpDown(5, p, resultPrice));
            Console.WriteLine(UpDown(6, p, resultPrice));
            Console.WriteLine(UpDown(7, p, resultPrice));
            Console.WriteLine(UpDown(8, p, resultPrice));
            Console.WriteLine(UpDown(9, p, resultPrice));
            Console.WriteLine(UpDown(10, p, resultPrice));

            Console.ReadKey();
        }

        /// <summary>
        /// 带备忘录的自顶向下的切割
        /// </summary>
        /// <param name="n"></param>
        /// <param name="p"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private static int UpDown(int n, int[] p,int[] result)
        {
            if (n == 0) return 0;//递归结束条件,当钢条长度为0,结束

            if(result[n]!=0)//如果已经计算过
            {
                return result[n];
            }
            int tempMaxPrice = 0;
            for (int i = 1; i <= n; i++)
            {
                int maxPrice = p[i] + UpDown(n - i, p,result);
                if (maxPrice > tempMaxPrice)
                {
                    tempMaxPrice = maxPrice;
                }
            }
            result[n] = tempMaxPrice;//将计算的子问题价格保存
            return tempMaxPrice;
        }
    }
}

3.3自顶向上-动态规划

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _508_钢条切割_自底向上_动态规划_
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] resultPrice = new int[11];//储存计算过的钢条切割后价格

            int[] p = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表,索引值代表钢条长度,值代表价格
            Console.WriteLine(BottomUp(0,p,resultPrice));
            Console.WriteLine(BottomUp(1, p, resultPrice));
            Console.WriteLine(BottomUp(2, p, resultPrice));
            Console.WriteLine(BottomUp(3, p, resultPrice));
            Console.WriteLine(BottomUp(4, p, resultPrice));
            Console.WriteLine(BottomUp(5, p, resultPrice));
            Console.WriteLine(BottomUp(6, p, resultPrice));
            Console.WriteLine(BottomUp(7, p, resultPrice));
            Console.WriteLine(BottomUp(8, p, resultPrice));
            Console.WriteLine(BottomUp(9, p, resultPrice));
            Console.WriteLine(BottomUp(10, p, resultPrice));

            Console.ReadKey();
        }

        private static int BottomUp(int n,int[] p,int[] result)
        {
            int tempMaxPrice = -1;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=i;j++)
                {
                    int maxPrice = p[j] + result[i - j];

                    if(maxPrice>tempMaxPrice)
                    {
                        tempMaxPrice = maxPrice;
                    }
                }
                result[i] = tempMaxPrice;
            }
            return result[n];
        }
    }
}

猜你喜欢

转载自blog.csdn.net/a962035/article/details/79943708