赞
踩
本文总结了《王道机试指南》中动态规划(Dynamic Programming)部分的所有例题以及分析思路、状态转移方程等。有助于完整复习动态规划全部内容。为避免大量代码和题干导致失去主线,本文只写思路,代码可在题目链接内的讨论区找到。
与分治法类似,其基本思想也是将待求解问题分解成若干子问题,先求解子问题,然后从这些子问题的解中得到原问题的解。
与分治法不同的是,分治法会使得有些子问题被重复计算多次。而动态规划的做法是将已解决子问题的答案保存下来,在需要子问题答案的时候便可直接获得,而不需要重复计算,节约效率。
状态转移方程:dp[n] = dp[n-1] + dp[n-2]
设置一个数组dp[ ],令dp[i]表示以A[i]作为末尾的连续序列的最大和。
状态转移方程:dp[i] = max{ A[i], dp[i-1] + A[i] }
解释:由于dp[i]是以A[i]作为结尾的连续序列最大和,因此只有两种情况:
dp[i] = A[i]
。dp[i] = dp[i-1] + A[i]
。所以取最大值即可。
对于二维情况,假设原二维矩阵的最大子矩阵所在的行为 i 到 j 。
同样设置一个数组dp[ ] ,表以A[i]作为末尾的最长递增子序列的长度。
状态转移方程:dp[i] = max{ 1, dp[j] + 1 }。(当 j < i && A[j] < A[i] 时)
解释:由于dp[i]是以A[i]作为末尾的最长递增子序列的长度,因此只有两种情况:
dp[j] + 1
存入dp[i]
。则最长递增子序列的长度即为dp中的最大值。
该题目中,用dp表示的便不是长度了,而是以A[i]作为末尾的最大上升子序列和。其原理与求最长递增子序列的原理完全一致。
状态转移方程:dp[i] = max{ A[i], dp[j] + A[i] }。(当 j < i && A[j] < A[i}时)
。
这道题有点难,有时间再琢磨。
这里要设置一个二维的数组 dp[][]。dp[i][j]
表示以S1[i]作为末尾和以S2[j]作为末尾的最长公共子序列的长度。因此通过设置这样一个数组,最长公共子序列的长度便是数组dp[n][m]
的值。
仔细说来,S1[i]和S2[j]的关系可分为两种情况:
S1[i] == S2[j]
,即两个字符相同。此时必定存在一个最长公共子串以这个字符结尾。其他部分等价于S1中前 i - 1 个字符和S2中前 j - 1 个字符的最长公共子串。则这个子串的长度比dp[i-1][j-1]
多1。即dp[i][j] = dp[i-1][j-1] + 1
。S1[i] != S2[j]
,那此时最长公共子串为S1中的前 i - 1 个字符和S2中的前 j - 1 个字符中最长公共子串长度的较大者。即dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }
。即
状态转移方程 | 条件 |
---|---|
dp[ i ] [ j ] = dp[ i - 1 ] [ j - 1 ] + 1 | S1[ i ] == S2[ j ] |
dp[ i ] [ j ] = max{ dp[ i - 1 ] [ j ], dp[ i ] [ j - 1 ] } | S1[ i ] != S2[ j ] |
但还要注意一下边界情况,当有一个字符串为空时,公共串长度必为0。即dp[i][0] == dp[0][j] == 0
。
相对于暴力枚举的O(2m+n)复杂度降至了O(mn)。
该问题描述的是,有n件物品,每件物品的重量为w[i],其价值为v[i],现在有个容量为m的背包,如何选择物品使得装入背包物品的价值最大。
如果暴力枚举所有排列组合,再从中找到最大一组,则时间复杂度为O(2n),下面以O(mn)的时间复杂度解决此问题。
首先设置一个二维数组dp[][],令dp[i][j]表示前 i 个物品装进容量为 j 的背包能获得的最大价值。通过设置这么一个二维数组,数组dp[n][m]值就是0-1背包问题的解。
只考虑第i件物品时,可将情况分为是否放入第i件物品两种:
dp[i][j] = dp[i-1][j]
。dp[i][j] = dp[i-1][ j-w[i] ] + v[i]
。综上,可得状态转移方程:dp[i][j] = max{ dp[i-1][j], dp[i-1][ j-w[i] ] + v[i] }
。
转移时要注意j-w[i]的值是否为非负值,若为负则代表当前容量无法放入第i件物品,不能进行转移。
再考虑一下边界情况:
所以,dp[i][0] = dp[0][j] = 0
。
链接:https://www.nowcoder.com/questionTerminal/4f0c1e21010e4d849bde5297148e81d9?f=discussion
来源:牛客网
User: 菜鸟葫芦娃
dp(m,n) = dp(m,m)
dp(m,n) = dp(m,n-1)
。dp(m,n) = dp(m-n,n)
。dp(m,n) = dp(m,n-1) + dp(m-n,n)
。#include <stdio.h> int dp(int m, int n) { if(n==1) return 1; else if(m==0) return 1; else if(n>m) return dp(m, m); else return dp(m, n-1)+dp(m-n, n); } int main() { int m, n; while(scanf("%d %d", &m, &n)!=EOF) { printf("%d\n", dp(m, n)); } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。