这是一篇很easy的入门版本的动态规划

又是一个美美的周末,追完几部小番

没错,如题,这是一篇很easy的入门版本的动态规划。当然虽然质量不高,但是秉持着种田的厚实,我也会认真完成的。 

                                            

首先是动态规划的概念,维基百科讲解得很详细,可以详细看一遍,里面列举出了很多例子:

en.wikipedia.org/wiki/Dynami…

像计算机科学中的 Fibonacci、Dijkstra 等等,以及经济学、运筹学等领域涉及到的动态规划的一些例子。

一句话总结,动态规划就是:将问题分解为子问题然后递归地找到子问题的最优解来最佳地解决问题,因此具有 最优子结构。(最优子结构也就是说每个子问题的解也是最优解)。

主要是两个例子:

1、0-1 背包问题

问题描述:有 N 件物品和一个容量为 V 的背包,放入第 i 件物品耗费的费用是 Ci,得到的价值是 Wi。求解将哪些物品装入背包可以使价值总和最大?

0 -1 背包 的意思也就是 每种物品仅有一件,可以选择放或不放

用子问题定义状态:即 F[i, v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:

                  F[i,v] = max {F[i-1,v],F[i-1,v-Ci]+Wi}

方程的意思就是:放到第i件物品的时候,这个时候的最大值取决于i-1的价值以及放 i 的之后的价值两者的最大值,这样就转移到了i-1物品相关的问题上,如果不放i,那么最大价值就是F[i-1,v],如果放 i 的话,最大价值就是 F[i-1,v-Ci]+Wi

实现如下:


ok,0-1背包完成

接下来,稍微优化下空间复杂度:

以上方法的时间和空间复杂度均为O(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到O(V )。

可以得知,当不装入i 时:

F[i][j] = F[i - 1][j]
复制代码

我们现在的目的是:

能不能保证第i次循环结束后 F[v] 中表示的就是我们定义的状态 F[i, v] 呢?

即:

F[j] = Math.max(F[j], F[j - w[i]] + v[i]);
复制代码

可以的,为什么这么说呢:

一个最直白的解释就是,等于号是先从右边开始算起,然后赋值给左边,即:

比如  sum = sum + k 这个等式里面,右边的肯定是上一个状态的 sum 的值,我们把上一个状态的值表示成: F[i-1],左边的 sum 是本次更新之后当前状态的值,即: F[i],也就是说

F[i] = F[i-1] + k   等价于   sum = sum + k 

那么,可以得到优化之后的代码:


2、最大连续子数组

题目描述如下:


题目的意思就是:在一个数组里面找出一个连续的子数组,保证他们的和在所有连续子数组里面是最大的。

首先,在数组 nums 中,可以得知,nums[i] 要得到一个更大的数字,肯定是需要加上一个大于 0 的数字,否则结果小于或者等于本身。

那么,问题就可以拆分成:要求到某个位置 i 的连续子数组的最大值,记为 F[i],等于到位置 (i-1) 的连续子数组的最大值与 nums[i] 的和,然后和 nums[i] 做一个比较,取出其中最大的

根据上面 0-1 背包 可以得知:

F[i] = F[i-1] + k 等价于 sum = sum + k 

可以得到解法如下:


3、最后,还有一道类似的水题:

题目:矩阵最小路径和

描述:有一个矩阵 rectangle,简称 r,从左上角开始走,前进方向每次只能向右或者向下,终点是右下角,经过的路径所有的数字加起来就是路径的和,求所有路径中最小的路径和。如下图:


解:略。。。

以上便是动态规划的简单介绍,更多进一步的学习推荐

  • 背包问题九讲
  • 北大poj 的一些练习题目
  • leetcode、lintcode 等等

有不对地方欢迎指出哈。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值