模型:
N件物品和容量为M的背包,第i件物品的体积是ci,价值是vi。
求装入背包物品的最大价值
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
fi,v表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:fi,v=maxfi−1,v,fi−1,v−ci+wi。
所以直接上代码……
#include <bits/stdc++.h>
using namespace std;
int c[1010], w[1010], dp[1010][1010], n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1;i <= n; i++) scanf("%d%d", &c[i], &w[i]);
for (int i = 1;i <= n; i++)
for (int j = 1;j <= m; j++)
if (j < c[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - c[i]] + w[i]);
printf ("%d\n", dp[n][m]);
return 0;
}
优化1:滚动数组
我们发现每一个dpi,只和上一次的dpi−1,有关,所以可以用滚动数组进行优化:
#include <bits/stdc++.h>
using namespace std;
int c[1010], w[1010], dp[2][1010], n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1;i <= n; i++) scanf("%d%d", &c[i], &w[i]);
for (int i = 1;i <= n; i++)
for (int j = 1;j <= m; j++)
if (j < c[i]) dp[i & 1][j] = dp[(i - 1) & 1][j];
else dp[i & 1][j] = max(dp[(i - 1) & 1][j], dp[(i - 1) & 1][j - c[i]] + w[i]);
printf ("%d\n", dp[n & 1][m]);
return 0;
}
这样,空间复杂度从O(nm)降低为O(m),节省了很多空间。
优化2:一维数组
外层循环到第i个物品的时候,fj表示背包中放入体积为j的物品的最大价值
#include <bits/stdc++.h>
using namespace std;
int c[1010], w[1010], dp[1010], n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1;i <= n; i++) scanf("%d%d", &c[i], &w[i]);
for (int i = 1;i <= n; i++)
for (int j = m; j >= c[i]; j--)
dp[j] = max(dp[j], dp[j - c[i]] + w[i]);
printf ("%d\n", dp[m]);
return 0;
}
01被曝是啥
。。。
哈哈哈