Skip to content

Latest commit

 

History

History
88 lines (50 loc) · 2.65 KB

File metadata and controls

88 lines (50 loc) · 2.65 KB

DP(Dynamic Programming)

理解“重叠子问题”和“最优子结构”

我们之前学过分治,分治策略就是将原问题划分成n个规模较小独立的而结构和原问题相似的子问题,递归的求解子问题,然后合并结果得到原问题的解。

而dp的子问题不是独立的,而是重叠的,也就是各子问题包含公共的子子问题。我们不需要重复的求解公共的子子问题,而是对每个子子问题只求解一次,然后纪录下来。动态规划用于解决最优化问题,所以每个子问题也是最优解。

动态规划的本质是,对问题的状态状态转移方程的定义。

经典dp问题

1.最大连续子段和(leetcode 53. Maximum Subarray)

状态:dp[i]表示以i为结尾的最大连续子段和

状态转移方程:dp[i] = max(dp[i-1] + nums[i], nums[i])

2.数字三角形问题,从顶部走到底部的最大和(poj 3176 )

状态:dp[i][j]表示从顶部(0,0)走到(i,j)的最大和

状态转移方程:dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + map[i][j]

类似题目 leetcode 62. Unique Paths

3.最长上升子序列LIS(leetcode 300. Longest Increasing Subsequence)

状态:dp[i]表示以i为结尾的最长上升子序列长度

状态转移方程:dp[i] = max(dp[0], dp[1], ... dp[j])+1 (其中0<=j<i dp[i]>dp[j])

4.最长公共子序列LCS(poj 1458)

状态:dp[i][j]表示a串中0~i和b串中0~j的子串的最长公共子序列长度

状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]+(a[i] == b[j]))

5.01背包问题(poj 3624)

题目描述:有N件物品和一个容量为V的背包,第i件物品的费用是c[i],价值是w[i],问将哪些物品装入背包能使价值总和最大。每种物品仅有一件。

状态:dp[i][j]表示前i件物品放入容量为j的背包可以获得的最大价值

状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i-1][j-c[i]] + w[i])

类似题目:leetcode 416. Partition Equal Subset Sum

优化空间复杂度:

1.滚动数组dp[2][V]

for(int i = 0; i < N; i++)
{
	int id = i&1;
  	for(int j = 0; j <= V; j++)
  	{
    	dp[id][j] = max(dp[id^1][j], dp[id^1][j-c[i]]+w[i]);//伪代码,条件自己判断
  	}
}

2.二维dp压缩成一维dp,去掉第一维,逆序推导dp[j]。

for(int i = 0; i < N; i++)
{
  for(int j = V; j >= c[i]; j--)
  {
    dp[j] = max(dp[j], dp[j-c[i]] + w[i]);
  }
}

注意:初始化、边界条件

DP在路上~~

各种各样的dp......

dp是思维难度大于编程难度的算法。