文章目录

  • 动态规划算法(Dynamic Programming)
    • 动态规划问题的属性
    • 应用实例:最长公共子序列问题(Longest Common Subsequence, LCS)
  • 贪心算法(Greedy Algorithm)
    • 贪心算法的属性
    • 应用实例:活动选择问题
  • 动态规划与贪心算法
    • 01背包问题
      • 状态机的考虑方法
    • 分数背包问题

动态规划算法(Dynamic Programming)

动态规划问题的属性

  动态规划问题一般有两个性质。

性质一:最优子结构性质,即问题实例(关于问题实例,举个例子,排序是问题,输入一串具体的待排序的数就是问题实例)的最优解包含子问题的最优解。也就是说我们的问题可以抽象出父问题关于子问题的递推关系式(dp的重点)。

  但是仅有性质一,我们完全可以用递归法来解决。性质二的出现引出了动态规划算法。

性质二:重叠子问题性质,即根据性质一得到的递推关系式,用递归法解决,存在很多重复的子问题被反复计算。

  针对性质二,我们可以利用备忘录法,即存储计算过的子问题,下次碰到就不再计算。但是存储计算过的子问题,会额外增加存储空间的开销。因此引出了自底向上的动态规划算法,自底向上的意思是,我们先从最简单的子问题开始求解,引出更复杂的子问题的解,最终求出问题实例的解。

  设计优秀的动态规划算法,意识十分重要,其重点是,是否能找到合适的父问题关于子问题的递推关系式。一些问题的动态规划解法,并不能直接求出最终的解,而是求一个中间过程解,通过中间过程解在设计求出最终解,例如下面的最长公共子序列问题。

应用实例:最长公共子序列问题(Longest Common Subsequence, LCS)

问题描述:
  求出X,Y的一个最长公共子序列
输入:
  X:A,B,C,B,D,A,BX:A, B, C, B, D, A, BX:A,B,C,B,D,A,B
  Y:B,D,C,A,B,AY:B, D, C, A, B, AY:B,D,C,A,B,A
输出:
  BDABBDABBDAB 或BCABBCABBCAB 或 BCBABCBABCBA

分析:
  暴力法,设XXX的长度是mmm,YYY的长度是nnn,找出XXX的所有子序列,时间复杂度O(2m)O(2^{m})O(2m),在YYY中查找是否有对应的子序列,时间复杂度O(n⋅2m)O(n·2^{m})O(n⋅2m),指数阶时间复杂度速度很慢。

  设XXX的长度是mmm,YYY的长度是nnn,令C[i,j]C[i,j]C[i,j]表示,截取XXX的索引从1到iii,同时截取YYY的索引从1到jjj的子序列的最长公共子序列的长度(这是一个中间过程解),我们并没有一开始就定义最长子序列是什么,而是计算最长子序列的长度,最后通过回溯法重建最长子序列。这样我们就不难得到递推表达式:C[i,j]={C[i−1,j−1]+1ifX[i]=Y[j]max(C[i−1,j],C[i,j−1])ifX[i]≠Y[j]C[i,j]=\begin{cases} C[i-1,j-1]+1~~& if~~X[i]=Y[j] \\ max(C[i-1,j],C[i,j-1]) ~~&if~~ X[i] \neq Y[j] \end{cases}C[i,j]={C[i−1,j−1]+1  max(C[i−1,j],C[i,j−1])  ​if  X[i]=Y[j]if  X[i]​=Y[j]​

计算最长公共子序列的长度的问题就满足上面的性质一,根据这个递推表达式,我们可以建立递归的方法来执行,但是不难发现,如果想要知道C[i,j−1]C[i,j-1]C[i,j−1]与C[i−1,j]C[i-1,j]C[i−1,j]的结果(假设X[i]≠Y[j−1]X[i] \neq Y[j-1]X[i]​=Y[j−1], X[i−1]≠Y[j]X[i-1] \neq Y[j]X[i−1]​=Y[j]),我们均需要求C[i−1,j−1]C[i-1,j-1]C[i−1,j−1]的结果,这就导致了C[i−1,j−1]C[i-1,j-1]C[i−1,j−1]需要被计算两次,计算最长公共子序列的长度的问题就满足上面的性质二,我们可以利用备忘录法,也就是判断C[i−1,j−1]C[i-1,j-1]C[i−1,j−1]在之前是否被计算,并保存计算结果,避免重复计算,但是这样就增加了保存计算结果的存储开销。

  下面就利用动态规划法来解决,动态规划法就是把执行顺序变成自底向上,所以我们优先要知道初始状态。这一问题中,我们需要知道的初始状态包括C[0,j]C[0,j]C[0,j]以及C[i,0]C[i,0]C[i,0],即X,YX,YX,Y有一个为空的情况,不难推断出:C[i,0]=0C[0,j]=0C[i,0]=0 \\ C[0,j]=0C[i,0]=0C[0,j]=0

接下来我们就自底向上,循环求解,时间复杂度O(mn)O(mn)O(mn),python示意代码如下:

# 初始化C[i,0], C[0,j] = 0
for j in range(1,n):for i in range(1,m):if X[i] == Y[j]:C[i,j] = C[i-1,j-1] + 1else:C[i,j] = max(C[i-1,j],C[i,j-1])

我们用下面的图来表示该算法执行步骤:

动态规划的问题在找到递推关系式后,我们都可以建立动态规划表(DP table),如上图二维表,当然还可能是一维、三维等。上图两条垂直直线把图像分成四部分,右下部分就是C[i,j]C[i,j]C[i,j]的值,i=0,1…m,j=0,1…ni=0,1\dots m,j=0,1\dots ni=0,1…m,j=0,1…n,红圈就是发生X[i]=Y[j]X[i]=Y[j]X[i]=Y[j]的地方,对应的C[i−1,j+1]C[i-1,j+1]C[i−1,j+1]用篮圈表示,两者之间用箭头连接。

这样我们就求出来了最长公共自序列的长度,具体的最长公共子序列需要我们用回溯法构建,下图就是利用回溯法,回溯法的解空间就是上面的CCC,python示意代码如下。

import copyrt = [] # 用于保存最终的输出
tmp = [] # 用于保存每一个LCS
X = ['A', 'B', 'C', 'B', 'D', 'A', 'B']
Y = ['B', 'D', 'C', 'A', 'B', 'A']def backtrack(n, m, X, Y, rt, tmp, num):"""一行一行的进行回溯Input------n是当前第几层m表示当前层需要从第m列开始遍历X是最长公共子序列问题输入中的XY是最长公共子序列问题输入中的Yrt用于保存最终的输出tmp用于保存每一个LCSnum是确定的最长公共自序列长度"""if (len(tmp) == num):rt.append(copy.deepcopy(tmp))  # 这里一定要用深拷贝!!!!returnif (n == len(Y)):returnfor i in range(m, len(X)):if(X[i] == Y[n]):tmp.append(Y[n])backtrack(n+1, i+1, X, Y, rt, tmp, num)del(tmp[-1])  # python的列表删除操作# 用tmp = tmp[:-1]删除不成功,使用id(tmp)可以看出,# python认为tmp=tmp[:-1]生成的tmp是新生成的列表,和最初的tmp地址不一样。else:backtrack(n+1, i, X, Y, rt, tmp, num)backtrack(0, 0, X, Y, rt, tmp, 4)
print(rt)# 输出
# [['B', 'C', 'B', 'A'], ['B', 'C', 'A', 'B'],
#  ['B', 'D', 'A', 'B'], ['B', 'D', 'A', 'B']]

上面算法输出4条最长公共子序列,其中有一个重复,你能找出重复的路径吗?最长公共子序列的三条路径(绿线表示)如下:


贪心算法(Greedy Algorithm)

贪心算法的属性

  贪婪(心)算法要求每一次选择时,都选择局部最优的选择,当把这些选择累计起来得到的全局解,也是全局最优解。换句话说,想要使用贪婪算法,问题同样必须具有最优子结构,同动态规划不同的是,我们要用贪心选择来改写一般的动态规划的最优子结构。但并不是所有的最优子结构都可以有贪心选择来改写,如果问题可以改用贪心选择来改写最优子结构,我们称这个问题具有贪心选择属性。

  贪心选择属性:我们可以通过作出局部最优的选择,来构造全局最优解。即贪心选择得到的解与剩余子问题的最优解的组合,就是全局最优解或全局最优解之一。在利用贪心算法求解时,我们需要先证明问题具有贪心选择属性

  动态规划问题一般是自下向上求解,贪心算法多数是自上向下,在一个大问题上我们进行贪心选择,得到一个贪心选择项加上一个子问题,在对子问题进行贪心选择。当然也有自下向上设计的贪心算法,例如最小生成树中用到的Prim算法。

应用实例:活动选择问题

  假设我们有n个活动a1,a2…ai…ana_{1}, a_{2} \dots a_{i} \dots a_{n}a1​,a2​…ai​…an​,活动开始时间分别是si,0≤i≤ns_{i} ,0 \leq i \leq nsi​,0≤i≤n,活动结束时间是fi,0≤i≤nf_{i} ,0 \leq i \leq nfi​,0≤i≤n,而这n个活动都需要占据某一个教室,且该教室在同一时间只能有一个活动占据。我们怎么安排活动,才能满足尽可能多的活动被执行(求n个活动的最优执行子集,这个最优执行子集往往不唯一),注意这n个活动已经按照结束时间进行了排序。其中一个问题实例如下;

i 1 2 3 4 5 6 7 8 9 10 11
s_{i} 1 3 0 5 3 5 6 8 8 2 12
f_{i} 4 5 6 7 9 9 10 11 12 14 16

  我们先用动态规划的思想分析这个问题,我们定义SijS_{ij}Sij​是在活动aia_{i}ai​结束之后开始,且在活动aja_{j}aj​开始之前结束的活动的集合,AijA_{ij}Aij​是活动集合SijS_{ij}Sij​的一个最优执行子集,SijS_{ij}Sij​的最优执行活动个数用c[ij]c[ij]c[ij]表示,AijA_{ij}Aij​包含的活动个数用∣Aij∣|A_{ij}|∣Aij​∣表示,假设AijA_{ij}Aij​包含活动aka_{k}ak​,则aka_{k}ak​一定也属于SijS_{ij}Sij​,不难知道aka_{k}ak​把AijA_{ij}Aij​分成了三个部分,分别是Aik,ak与AkjA_{ik},a_{k}与A_{kj}Aik​,ak​与Akj​,且有∣Aij∣=∣Aik∣+∣Akj∣+1|A_{ij}| = |A_{ik}|+|A_{kj}|+1∣Aij​∣=∣Aik​∣+∣Akj​∣+1

  我们可以证明,AikA_{ik}Aik​与AkjA_{kj}Akj​分别是SikS_{ik}Sik​与SkjS_{kj}Skj​的一个最优执行子集,下面用剪贴法证明。如果AikA_{ik}Aik​不是SikS_{ik}Sik​的一个最优执行子集,那么我么一定能找到集合Aik′A'_{ik}Aik′​包含更多的互斥活动,即∣Aik′∣>∣Aik∣|A'_{ik}|>|A_{ik}|∣Aik′​∣>∣Aik​∣,那么存在Aij′A'_{ij}Aij′​满足∣Aij′∣=∣Aik′∣+∣Akj∣+1|A'_{ij}| = |A'_{ik}|+|A_{kj}|+1∣Aij′​∣=∣Aik′​∣+∣Akj​∣+1,且∣Aij′∣>∣Aij∣|A'_{ij}|>|A_{ij}|∣Aij′​∣>∣Aij​∣,进而推出AijA_{ij}Aij​不是活动集合SijS_{ij}Sij​的一个最优执行子集,与我们之前的假设不符,所以AikA_{ik}Aik​一定是SikS_{ik}Sik​的一个最优执行子集,同理,AkjA_{kj}Akj​一定是SkjS_{kj}Skj​的一个最优执行子集,所以我么有下面的递推关系式c[ij]=c[ik]+c[kj]+1c[ij] = c[ik]+c[kj]+1c[ij]=c[ik]+c[kj]+1

由于我们事先定义了,aka_{k}ak​一定在AijA_{ij}Aij​中,实际执行时,我们并不知道aka_{k}ak​具体指的是哪个活动,所以我们的递推关系式要更改成c[ij]=max⁡k(c[ik]+c[kj]+1)c[ij] = \max_{k}(c[ik]+c[kj]+1)c[ij]=kmax​(c[ik]+c[kj]+1)加上边界条件,我们就得到了真正的递推关系式c[ij]={0Sij=∅max⁡k(c[ik]+c[kj]+1)否则c[ij] = \begin{cases} 0 & S_{ij} = \varnothing \\ \max \limits_{k}(c[ik]+c[kj]+1) & 否则 \end{cases}c[ij]={0kmax​(c[ik]+c[kj]+1)​Sij​=∅否则​

  可见活动选择问题是满足最优子结构性质的,同时也不难想到活动选择问题具有很多的重复子结构,可以利用自下向上的动态规划算法。

  现在我们考虑利用贪心选择简化这个算法,我们的直观感受是,如果这个活动尽早结束,那么这个教室就能越早被腾出来,那后面的可供选择的活动就更多,这个教室就越有可能被更多的活动利用。具体来看,就是我们在上面动态规划得到的递推式中,每一步总是贪心的选择最早结束的活动为aka_{k}ak​,由于活动已经按照结束时间进行了排序,所以我们直接取SijS_{ij}Sij​中的第一个活动即可。这样如果可行,c[ik]=0c[ik]=0c[ik]=0,我们直接省去了一个子结构,同时也省去了选取最合适的kkk,确实简化了算法。下面我们证明贪心选择做出的局部最优解选择,恰好也是全局最优解在这里的选择之一(这里用的不是剪贴法)。

  我们每一步总是贪心的选择最早结束的活动为aka_{k}ak​,由于AijA_{ij}Aij​是SijS_{ij}Sij​众多最优执行子集中的一个,不一定就包含aka_{k}ak​,如果AijA_{ij}Aij​包含aka_{k}ak​,那么直接证毕;如果AijA_{ij}Aij​不包含aka_{k}ak​,设AijA_{ij}Aij​中最早结束的活动是ak′a'_{k}ak′​,那么ak′a'_{k}ak′​的结束时间就一定比aka_{k}ak​晚,所以我们用aka_{k}ak​替换ak′a'_{k}ak′​得到的AijA_{ij}Aij​依然可以作为SijS_{ij}Sij​的最优执行子集,证毕。所以贪心选择是可以替换动态规划的最优子结构,我们得到贪心选择的递推公式如下c[ij]=1+c[kj]c[ij]=1+c[kj]c[ij]=1+c[kj]其中aka_{k}ak​是SijS_{ij}Sij​中最早结束的活动,我们可以得到之前的问题实例的一个解:a1,a4,a8,a11a_{1}, a_{4}, a_{8}, a_{11}a1​,a4​,a8​,a11​。

  最后说明一下,选择最早结束的活动,并不是活动选择问题的唯一贪心选择方法。


动态规划与贪心算法

  前面我们知道,动态规划要满足两个属性,最优子结构属性和重叠子问题属性,贪心算法同样要满足最优子结构属性,不过有时我们可以用贪心选择替代最优子结构,这样我们可以把复杂的动态规划问题,变成使用贪心算法的更简单的问题。但是并不是所有的动态规划问题,都可以由贪心算法求解,其中最著名的问题就是01背包问题。

01背包问题

  假设一个小偷带着一个最大承重量为WWW磅的背包去偷窃,有nnn个物品可供偷窃,每个物品的价值是viv_{i}vi​,每个物品的重量是wiw_{i}wi​磅,每个物品只能是拿或者不拿两种选择,而不能只拿一部分。请问,小偷怎么选择物品,才能获得最大的收益。其中一个问题实例如下,背包承重量是8:

i 1 2 3 4
v_{i} 3 4 5 6
w_{i} 2 3 4 5

  我们用动态规划的方法分析这个问题。由于每个物品,我们只能选择拿或者不拿,我们定义c[i,j]c[i,j]c[i,j]为包的最大容量为jjj,且只考虑编号≤i\leq i≤i的物品拿与不拿后,小偷获得的最大收益。那么c[i,j]c[i,j]c[i,j]与子问题的关系就是c[i,j]=max(c[i−1,j],c[i−1,j−wi]+vi)c[i,j]=max(c[i-1,j], ~~c[i-1,j-w_{i}]+v_{i})c[i,j]=max(c[i−1,j],  c[i−1,j−wi​]+vi​)

即对于编号为iii的物品,小偷会选择拿与不拿,如果选择不拿,或者剩余空间不够,小偷不得不选择不拿,则到编号为iii的物品为止,小偷拿的东西的价值和到前i−1i-1i−1个是一样的;如果小偷选择拿,则到编号为iii的物品为止,小偷拿的东西的价值是到前i−1i-1i−1个物品且在包的容量减去wiw_{i}wi​时的最大价值(既然选择了拿第iii个物品,就一定要腾出一定重量去拿),在加上第iii个物品的价值viv_{i}vi​。具体过程见下表

j=0 j=1 j=2 j=3 j=4 j=5 j=6 j=7 j=8
i=0 0 0 0 0 0 0 0 0 0
i=1 0 0 3 3 3 3 3 3 3
i=2 0 0 3 4 4 7 7 7 7
i=3 0 0 3 4 5 7 8 9 9
i=4 0 0 3 4 5 7 8 9 10

状态机的考虑方法

  很多问题,我们用状态机的方法分析,会更容易写出递推关系式,状态机需要我们明确状态和动作,动作往往很容易找到,状态要困难一些。

  以01背包问题为例,动作很简单,就是拿与不拿,动作也决定了状态的转移,我们在状态s1s_1s1​下执行某一动作,就会转移到状态s2s_2s2​(当然不排除s1s_1s1​与s2s_2s2​是相同状态的情况),现在我们看看状态有哪些因素确定,首先我们把01背包建模成扫描任务,即在第一时刻确定是否拿第一个物品,第二时刻确定是否拿第二个物品,依次往后,那很明显,我们处在不同时刻,我们会决定是否拿该时刻对应的物品,不同的时刻,确定拿不同的物品,这区分了不同的状态,我们用iii表示当前状态要考虑的物品;同时,背包容量不是无限的,所以背包剩余容量也应该区分了不同的状态,我们用jjj表示背包剩余容量,那么二元组(i,j)(i,j)(i,j)就可以表示状态,你可以看一下,改变i,ji,ji,j中任何一个,我们就会处于不同的状态。

  如上图,如果iii固定,则状态还可能有9个,同理,i−1i-1i−1或i+1i+1i+1固定,候选状态也是9个,单看(i,3)(i,3)(i,3),他只可能从(i−1,3)(i-1,3)(i−1,3)和(i−1,3+wi)(i-1,3+w_i)(i−1,3+wi​)状态得到,如果用dp[i,j]dp[i,j]dp[i,j]表示处于状态(i,j)(i,j)(i,j)的最大价值,由于他只能从两个状态得到,只需取这两个路径的最大值,就是这个状态的最大价值。

dp[i,3]=max(dp[i−1,3],dp[i−1,3+wi]+vi)dp[i,3]=max(~dp[i-1,3],~dp[i-1,3+w_i]+v_i)dp[i,3]=max( dp[i−1,3], dp[i−1,3+wi​]+vi​)

这里dp[i,j]dp[i,j]dp[i,j]表示的已经执行了动作之后的(i,j)(i,j)(i,j)状态的最大价值,单看(i,8)(i,8)(i,8),他只可能从(i−1,8)(i-1,8)(i−1,8)状态得到,故

dp[i,8]=dp[i−1,8]dp[i,8]=dp[i-1,8]dp[i,8]=dp[i−1,8]

所以,递推关系式可以表示为:

dp[i,j]={max(dp[i−1,j],dp[i−1,j+wi]+vi)j+wi<=wmaxdp[i−1,j]j+wi>wmaxdp[i,j]=\left\{ \begin{array}{rcl} &max(~dp[i-1,j],~dp[i-1,j+w_i]+v_i) & j+w_i<=w_{max}\\ &dp[i-1,j] & j+w_i>w_{max} \end{array} \right.dp[i,j]={​max( dp[i−1,j], dp[i−1,j+wi​]+vi​)dp[i−1,j]​j+wi​<=wmax​j+wi​>wmax​​

  其实这是一种穷举,我们穷举了所有状态的最大价值,如果用代码表示应该是

# python
v = [0, 3, 4, 5, 6]
w = [0, 2, 3, 4, 5]
dp = [[0 for ii in range(9)] for i in range(4+1)]for i in range(1, 5):for ii in range(9):if ii + w[i]<=8:dp[i][ii] = max(dp[i-1][ii], dp[i-1][ii+w[i]]+v[i])else:dp[i][ii] = dp[i-1][ii]print(dp)# 结果“”“[[0, 0, 0, 0, 0, 0, 0, 0, 0],[3, 3, 3, 3, 3, 3, 3, 0, 0],[7, 7, 7, 7, 4, 4, 3, 0, 0],[9, 9, 8, 7, 5, 4, 3, 0, 0],[10, 9, 8, 7, 5, 4, 3, 0, 0]]”“”

分数背包问题

  分数背包问题是01背包问题的变形形式,对于一个商品,小偷可以拿一部分(比如物品是金沙),请问,小偷怎么选择物品,才能获得最大的收益。分数背包问题,就可以利用贪心算法,一个具体的问题实例如下,背包容量是50

i 1 2 3
v_{i} 60 100 120
w_{i} 10 20 30

我们定义每个物品的每磅价值,即viwi\frac{v_{i}}{w_{i}}wi​vi​​

i 1 2 3
v_{i} 60 100 120
w_{i} 10 20 30
v_{i} / w_{i} 6 5 4

我们进行贪心选择时候,优先选择拿每镑价值大的物品,下面用剪贴法证明贪心选择属性。问题SkS_{k}Sk​是第k−1k-1k−1步以后的子问题,假设问题SkS_{k}Sk​的最优解为AkA_{k}Ak​,AkA_{k}Ak​中单位重量价值最大的物品是mmm,实际SkS_{k}Sk​中单位价值最大的物品是nnn,如果mmm不等于nnn,则我们用物品nnn替换AkA_{k}Ak​中的mmm的一部分,得到的新的解Ak′A'_{k}Ak′​价值一定大于AkA_{k}Ak​,与AkA_{k}Ak​是最优解矛盾,所以AkA_{k}Ak​中一定含有nnn。所以第k步的选择是Sk=ak+Sk+1S_{k} = a_{k}+S_{k+1}Sk​=ak​+Sk+1​

其中,aka_{k}ak​是SkS_{k}Sk​中单位重量价值最大的物品,Sk+1S_{k+1}Sk+1​是在第kkk步进行贪心选择后,剩余物品构成的子问题。

  针对这个问题实例,我们的解是编号是1和2的物品全拿,编号是3的物品只拿20镑。

  不难看出,这种贪心选择,无法应用到01背包问题中,按照上文中01背包的问题实例,按照这种贪心选择进行,只能拿走编号1和2的总计价值是7的物品。


参考文献:
《算法导论》
01背包:https://blog.csdn.net/u014296502/article/details/80015722
01背包:https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html
01背包与分数背包:https://blog.csdn.net/ii1245712564/article/details/45396833

动态规划(Dynamic Programming)与贪心算法(Greedy Algorithm)相关推荐

  1. 贪心算法(Greedy Algorithm)最小生成树 克鲁斯卡尔算法(Kruskal#39;s algorithm)

    克鲁斯卡尔算法(Kruskal's algorithm)它既是古典最低的一个简单的了解生成树算法. 这充分反映了这一点贪心算法的精髓.该方法可以通常的图被表示.图选择这里借用Wikipedia在.非常 ...

  2. 贪心算法 (Greedy Algorithm)

    贪心算法 如果要简要得描述这个算法的话就是,首先边的权重排序.(从小到大)循环的判断是否需要选择这里的边.判断的依据则是边的两个顶点是否已经连通,如果连通则继续下一条.不连通就选择使其连通. http ...

  3. 运筹学状态转移方程例子_动态规划 Dynamic Programming

    从运筹学和算法的角度综合介绍动态规划 规划论 Mathematical Programming / Mathematical Optimization In mathematics, computer ...

  4. 动态规划 dynamic programming

    动态规划dynamic programming June,7, 2015 作者:swanGooseMan 出处:http://www.cnblogs.com/swanGooseMan/p/455658 ...

  5. 贪心(Greedy Algorithm)

    贪心(Greedy Algorithm) 贪心 44.通配符匹配 45.跳跃游戏 II 55.跳跃游戏 122.买卖股票的最佳时机II 134.加油站 135.分发糖果 179.最大数 277.搜寻名 ...

  6. 动态规划(Dynamic Programming)的一些事一些情

    References <算法导论> 最近在回顾算法的知识,特将一些动态规划的重点记录下来,好让以后自己不要忘记. 基本概念 动态规划(Dynamic Programming,简称为DP,下 ...

  7. 算法导论-动态规划(dynamic programming)

    动态规划:通过组合子问题的解来解决整个问题. 动态规划的四个步骤: 1)描述最优解的结构: 2)递归定义最优解的值: 3)按自低向上的方式计算最优解的值(首先找到子问题的最优解,解决子问题,最后找到问 ...

  8. java贪心算法几个经典例子_经典算法思想5——贪心(greedy algorithm)

    贪心算法,是指在对问题求解时,总是做出再当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是某种意义上的局部最优解. 贪心算法没有固定算法框架,算法设计的关键是贪心策略的选择.必须注 ...

  9. 动态规划|Dynamic Programming

    由于最近课设要用动态规划,翻阅资料学习一下. 动态规划 解决复杂问题的方法,把它们分解成更简单的子问题. 一旦我们看到一些例子,这个定义就有意义了.实际上,我们今天只看解问题的例子 解决DP问题的步骤 ...

最新文章

  1. 工业软件研究框架_聚焦十四五!先进制造急先锋——工业软件
  2. python基础第二天(day14)
  3. 读书笔记:黑客与画家
  4. 深度洞见|体验经济浪潮兴起,什么才是企业制胜密钥?
  5. @class、#import
  6. virtualenvwrapper 的安装和使用
  7. Linux中Shell脚本函数库的笔记
  8. u盘解密软件_【精彩文章】基于STM32的指纹识别U盘设计
  9. 全向轮移动平台参数校准
  10. wrk -- 小巧轻盈的 http 性能测试工具.
  11. Solaris11修改主机名
  12. Oracle中UNION和ORDER BY共用方法
  13. 【免费】Discuz素材资源交易论坛整站源码/带数据整站源码打包
  14. 构建OctoberCMS插件:Google Analytics(分析)
  15. 光荣特库摩游戏《莱莎的炼金工房》宣布动画化,2023 年 7 月开播
  16. 中国首份国际贸易企业信息化发展白皮书发布,小满科技后劲十足
  17. linux英文字典,linux终端下的英文字典--SDCV(转)
  18. odoo审批流程实例
  19. 苏嵌//郑艳秋//2018.7.12
  20. 分享自己写的一个找CALL练习软件

热门文章

  1. 日记本java代码_简单的JAVA日记本程序源代码
  2. 浅谈Java对接阿里IOT
  3. C++ modbus TCP 协议跟PLC通信
  4. 六招帮你解决平面设计排版
  5. 内存卡android文件夹名称,安卓手机内存卡文件夹英文名称解析——第三方应用类...
  6. flink程序:Exceeded checkpoint tolerable failure threshould
  7. 计算机网络之应用层图解,秒解应用层HTTP,期末考试不担心!!
  8. Hyper-V自定义专用网络网段
  9. thinkphp内核家教平台网站源码带手机站
  10. TCP局域网服务器简易搭建(eps-01s)