动态规划是把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,解决这类过程优化问题的方法。
解法分类
解决动态思路规划问题有两种思路:一种是得到一个阶段的答案后推出所有与之直接相关的阶段的答案、另一种时由上一个阶段不断得到下一个阶段的答案。
背包问题
背包问题是最基础的动态规划问题,分为01背包、完全背包、多重背包等。
1、01背包
1.1 问题描述:有N件物品和一个容量为V的背包。第i件物品的费用(即体积,下同)是w[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
1.2 代码:
//f[v]为背包体积为v时的价值
for i = 1,2,..N
for v = V...0
f[v] = max(f[v] , f[v-w[i]+val[i]);
1.3 例题:01背包
2、完全背包
(注意与01背包的区别)
2.1 问题描述:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是w[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
2.1 代码:
2.2 例题:完全背包
for i =1,2,..,N
for v=0,...,V
f[v] = max(f[v] , f[v-w[i]+val[i]);
3、混合背包
3.1 问题描述:有些物体只能取一件,有些物体能取无限件。
3.2 分析:将问题转化为01背包问题,无限件物体可以变为v/w[i]件
4、二维背包问题
4.1 问题描述:限制条件有两个:V,U。
4.2 分析:只需要将f多加一维变成f[v][u]。
5、求背包问题的方案总数
5.1 问题描述:给定的背包问题,求获得最大价值的方案总数
5.2 算法:如01背包问题,f[i][v] = sum{ f[ i-1 ][ v ] , f[ i-1 ][ v-w[i] ] + c[i] },初始条件为f[0][0]=1;
5.3 例题:货币系统
6、多维背包+多维价值
6.1 问题描述:多个限制条件,多个价值条件。
6.2 算法:限制条件——dp的维数,价值条件——dp的个数
6.3 例题:找啊找啊找GF
转化为背包问题
P2392 kkksc03考前临时抱佛脚
天平问题:将一些数分成尽量相等的两份
解法:转化为背包问题,这两份中一定有一份小于等于all/2,所以设定背包容量all/2,每个数为价值,价值最大也就是最接近all/2;
区间dp问题
所谓区间dp,就是在一个区间上进行的dp, 一般通过将大区间分割成小区间进行dp。
区间型动态规划,又称为合并类动态规划,是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系。
区间DP伪代码:
for(int i=1;i<=n;i++)
{
dp[i][i]=初始值
}
for(int len=2;len<=n;len++) //区间长度
for(int i=1;i<=n;i++) //枚举起点
{
int j=i+len-1; //区间终点
if(j>n) break; //越界结束
for(int k=i;k<j;k++) //枚举分割点,构造状态转移方程
{
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
}
}
1、石子合并
1.1 问题描述:有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
1.2 思路:状态转移方程 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]) (dp[i][j]表示合并第i堆到第j堆的最小代价)
1.3 例题:环形石子合并 能量项链