动态规划

动态规划思想

动态规划的基本思想是把问题拆分成一个个相互联系的子问题,先求解子问题,最后将子问题合并形成最终的求解。其实质上是通过开辟记录表,记录已求解过的结果,当再次需要求解的时候,可以直接到那个记录表中去查找,从而避免重复计算子问题来达到降低时间复杂度的效果。实际上是一个空间换时间的算法。动态规划,通常可以把指数级的复杂度降低到多项式级别。

动态规划的两个重要性质:

1.子问题重叠性质:解决冗余,它对于重复出现的子问题,会在第一次求解后使用一个表储存下来,供之后使用,本质上也是一个空间换时间的思想。

举个例子:问1+2+3+4+5等于几,答案是15,那么我再后面再写个+6,答案呢,21,一下就算出来了,原因就在于我们已经有了前面计算的基础,只需要再前面的基础之上再+6就可以了,而如果直接问你1+2+3+4+5+6等于几,肯定是要慢很多的。

2.最优子结构性质:如果问题的最优解所包含的子问题的解也是最优的,则称为其具有最优子结构性质。它为动态规划解决问题提供了重要的线索。

应用:

在实际中应用动态规划是难点,关键在于动态规划虽然有诸多特点,但在实际问题中却没有一个通用的方法,它会因具体问题的不同而不同。

通常判断一个问题是否可以使用动态规划来解决,关键之一是判断有没有重复的子问题,除了我上面举得那个简单的例子之外,还有一个经典案例,就是斐波那契数列,都知道它的公式为f(n) = f(n-1) + f(n-2),也就是说我每求一个数都得去找他前两个数的值,而前两个数也是这么算来的所以斐波那契数列一般对第n项求值都是使用递归,然而递归是很低效的,但是如果我们在这里使用动态规划,使用一个value[i]的数组把每一项i计算之后的值都存在这个数组里,那么在之后的计算中就不必再进行冗余的计算,这就是动态规划的关键。(还有一个经典例子是寻找最长公共子字符串)

另外一个关键是在于有没有最优解结构。经典案例就是01背包问题:

假设中保险箱有 5 件宝物,大小分别是 3、4、7、8 和 9,其价值分别是 4、5、10、11、13,而且背包的容量为 i,要求在不超过背包容量的情况下取得最大价值的宝物。

这个问题就是一个典型的求最优解的问题,这个问题的解决思路就是把它拆分为求解一个个子问题,并且保证子问题的解也是最优的:

1.首先将第一个宝物放入,讨论背包大小为1-i时背包中的价值情况,求得一个最大价值;

2.之后再加入第二个宝物,讨论背包大小为1-i时背包中的价值情况,求得一个最大价值;

3.加入第三个宝物。。。

。。

直到宝物全部加入。

代码如下:

static void GetMaxValue(int capacity)
{
    int[] size = new int[] { 3, 4, 7, 8, 9 };
    int[] values = new int[] { 4, 5, 10, 11, 13 };
    int[] totval = new int[capacity+1];//储存背包容量为0-capacity时的最高价值
    int n = values.Length;//宝物数量
    for (int j = 0; j <= n - 1; j++)//遍历每一件宝物
    {
        for (int i = 0; i <= capacity; i++)//遍历不同大小的情况
        {
            if (i >= size[j])//当背包容量足以放得下宝物时,计算当前容量的最高价值
            {
                int temp = totval[i - size[j]] + values[j];//把当前宝物放入背包,再在totval数组找一个剩下的容量的最大价值(这里用到的就是子问题的重叠性)
                if (totval[i] < temp)//当数组中的这个值不为最优解了,就替换它
                {
                    totval[i] = totval[i - size[j]] + values[j];
                }
            }
        }    
    }
        
    Console.WriteLine("The maximum value is: " + totval[capacity])
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值