背包问题是动态规划中的一类经典问题。下面分别给出01背包问题、完全背包问题、多重背包问题和二维费用的背包问题的解决方案:
01背包问题
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
代码展示:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int N, V;
int v[1000], w[1000];
int dp[1010] = {0}; // dp的规模与背包的体积有关,多开辟一点空间防止溢出
cin >> N >> V;
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i];
}
for(int i = 0; i < N; i ++) // 背包问题永远都是先枚举数量
{
for(int j = V; j >= v[i]; j --) // 倒序枚举体积是为了保证状态i都是从i - 1转移过来的
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]); // 两种方案,取或不取
}
}
cout << dp[V];
return 0;
}
完全背包问题
有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。第 i 种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
代码展示:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int N, V;
int v[1000], w[1000];
int dp[1010] = {0};
cin >> N >> V;
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i];
}
for(int i = 0; i < N; i ++)
{
for(int j = v[i]; j <= V; j ++) // 与01背包问题的唯一区别:正序枚举体积,可以保证枚举到每件物品的任意数量
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
cout << dp[V];
return 0;
}
多重背包问题
有 N 种物品和一个容量是 V 的背包。第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。
代码展示:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int N, V;
int v[100], w[100], s[100];
int dp[110] = {0};
cin >> N >> V;
for(int i = 0; i < N; i++)
{
cin >> v[i] >> w[i] >> s[i];
}
for(int i = 0; i < N; i ++)
{
for(int j = V; j >= v[i]; j --) // 注意此处为倒序枚举体积
{
for(int k = 1; k <= s[i] && k * v[i] <= j; k ++)
{
dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]); // 枚举每种物品可以取的件数
}
}
}
cout << dp[V];
return 0;
}
二维费用的背包问题
有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。输出最大价值。
代码展示:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int N, V, M;
int v[1000], m[1000], w[1000];
int dp[110][110] = {0};
cin >> N >> V >> M;
for(int i = 0; i < N; i++)
{
cin >> v[i] >> m[i] >> w[i];
}
for(int i = 0; i < N; i ++)
{
for(int j = V; j >= v[i]; j --)
{
for(int k = M; k >= m[i]; k --) // 多加一层对质量的枚举即可
{
dp[j][k] = max(dp[j][k], dp[j - v[i]][k - m[i]] + w[i]);
}
}
}
cout << dp[V][M];
return 0;
}
其它背包问题
以上只提供了四种背包问题的解决方案,背包问题的其它变种还有:混合背包问题、分组背包问题、有依赖的背包问题、背包问题求方案数、背包问题求具体方案。以上九类问题称为背包九讲,基本涵盖了背包问题的所有变种。以上5种背包问题留待后续更新…