DP分析
1、背包问题(选择问题)
输入样例
4 5 1 2 2 4 3 4 4 5
输出样例:
8
2、要点分析
- 特点:每个物品仅能使用一次
重要变量&公式解释
f[i][j]:
表示所有选法集合中,只从前i个物品中选,并且总体积≤j的选法的集合,它的值是这个集合中每一个选法的最大值.(注意:这里的二维数组f可以把它看成是一个求最大值的函数,但是不用去实现。可看成函数两边左右抵消。便于理解可以直接把它当成最大值看待)- 状态转移方程:
f[i][j]
= max(f[i-1][j]
,f[i-1][j-v[i]]
+w[i]) f[i-1][j]
:不选第i个物品的集合中的最大值。f[i-1][j-v[i]]+w[i]
:选第i个物品的集合,但是直接求不容易求所在集合的属性,这里迂回打击一下,先将第i个物品的体积减去,求剩下集合中选法的最大值.
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> v[i] >> w[i];
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
//未选第i个元素
f[i][j] = f[i - 1][j];
if (j >= v[i])
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
cout << f[n][m] << endl;
return 0;
}
3、理解思路
-
第i个物品要么选,要么不选。
-
在一开始的时候自己对这个算法也是很迷,不清楚
f[i][j]
为什么能表示前i个物品的总体积小于j的总价值的最大值。后面才慢慢理解,在开始的时候可以看成存在这个求最大值的函数。int Fmax(int i , int j);(这里不用具体实现的细节),求出不包含第i个的最大值,和不包含第i个的最大值。取两者中的最大值就是所需。 -
for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++);这个循环中遍历了所有可能存在的结果的最大值。并把每一次结果的最大值放在二维数组中。最后f[n][m]
表示所有物品中的最大值。直接输出。 -
在这里我们把最大值结果的集合划分为两个部分。一、没选第i个物品的,最大值为前i-1个物品的价值的最大值
f[i-1][j]
。一、选了第i个物品的。由于选定了第i个物品,我们把第i个物品提取出来,那么前i-1个物品的最大值为f[i - 1][j - v[i]]
,最后再加上w[i]的价值。