「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
01背包后讲解完全背包,首先看一道01背包的例题
01背包求具体方案问题
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 1…N
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
物品编号范围是 1…N
数据范围
0<N,V≤1000 0<vi,wi≤1000
输入样例
4 5 1 2 2 4 3 4 4 6输出样例:
1 4
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
int w1[N], w2[N];
int dp[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) cin >> w1[i] >> w2[i];
for (int i = n; i >= 1; i -- )
for (int j = 0; j <= m; j ++ )
{
dp[i][j] = f[i + 1][j];
if (j >= w1[i]) dp[i][j] = max(dp[i][j], dp[i + 1][j - w1[i]] + w2[i]);
}
int j = m;
for (int i = 1; i <= n; i ++ )
if (j >= w1[i] && dp[i][j] == dp[i + 1][j - w1[i]] + w2[i])
{
cout << i << ' ';
j -= w1[i];
}
return 0;
}
完全背包问题
完全背包物品是无限个的。
n个物品(每个物品无限个),每个物品v体积,w价值,有m个背包,如何取价值最大化
分析
F[ i , j ] = max ( F [ i - 1 , j ] , F [ i , j - v] + w )
该公式表示:F[ i , j ] 从前 i 个物品中选出了总体积为 j 的物品放入背包的最大价值和
F [ i - 1 , j ] 表示未选第 i 个物品的最大价值
F [ i , j - v ] + w (条件:j >= v) 表示选第 i 个物品的最大价值(选1,2,3……个的总和)
模板
求最大价值
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
int f[N];
int main(){
cin >> n >> m;
for (int i = 1; i <= n; i ++ ){
int v, w;
cin >> v >> w;
for (int j = v; j <= m; j ++ )//注意和01背包的区别
f[j] = max(f[j - v] + w, f[j]);
}
cout << f[m] << endl;
return 0;
}
求方案数
#include <iostream>
using namespace std;
const int N = 1010;
int n;
int v[4] = {10, 20, 50, 100};//与01背包求方案数类似
int f[N];
int main()
{
cin >> n;
f[0] = 1;
for (int i = 0; i < 4; i ++ )
for (int j = v[i]; j <= n; j ++ )
f[j] += f[j - v[i]];
cout << f[n] << endl;
return 0;
}