目录
(1)0-1背包
题目描述
给一个能承重V的背包,和n件物品,我们用重量和价值的二元组来表示一个物品,第i件物品表示为(Vi,Wi),问:在背包不超重的情况下,得到物品的最大价值是多少?
输入
第一行输入两个数 V,n,分别代表背包的最大承重和物品数。
接下来n行,每行两个数Vi,Wi,分别代表第i件物品的重量和价值。
(Vi≤V≤10000,n≤100,Wi≤1000000)
输出
输出一个整数,代表在背包不超重情况下所装物品的最大价值。
样例输入1
15 4
4 10
3 7
12 12
9 8
样例输出1
19
数据规模与约定
时间限制:1 s
内存限制:64 M
100% 的数据保证(Vi≤V≤10000,n≤100,Wi≤1000000)
题解:
这道题我们选取的状态为:dp[i][j]代表前i件物品,选取的总体积最大为j时能获得的最大价值。然后我们可以利用容斥原理的思想去思考递推式:将状态整个分成两部分——选取了第i件物品的和没选取第i件物品的。其中没选取第i件物品的最大价值可以被表示为dp[i-1][j],至于选取了第i件物品的,我们可以按以下思路来想:我们先给第i件物品留好一个位置,这样再将所有结果列出即可,也就是:dp[i-1][j-v[i]]+w[i]。上面那个表达式解释一下就是:为第i个留好位置(也就是[j-v[i]]),再去计算没有i物品的且为物品i留有位置的所有的情况(也就是dp[i-1][j-v[i]]),最后再把第i个物品的的价值加上去即可。
值得一提的点是,这道题不需要我们特别地去设定初值。
代码:
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int dp[105][10005] = { 0 };//前i件物品,选取的总体积最大为j时能获得的最大价值
int w[105], v[105];
int main()
{
int V, N;
cin >> V >> N;
for (int i = 1;i <= N;i++)
{
cin >> v[i] >> w[i];
}
for (int i = 1;i <= N;i++)
{
for (int j = 1;j <= V;j++)
{
if (j >= v[i])//背包剩下的空间能放下第i件物品
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
else dp[i][j] = dp[i - 1][j];
}
}
cout << dp[N][V];
return 0;
}
(2)完全背包
题目描述
有N种物品和一个容量为 V 的背包,每种物品都有无限件可用。
第 i 种物品的体积是Ci,价值是Wi。求解在不超过背包容量的情况下,能够获得的最大价值。
输入
第一行为两个整数N、V(1≤N,V≤10000),分别代表题目描述中的物品种类数量N和背包容量V。
后跟N行,第 i 行两个整数Ci、Vi,分别代表每种物品的体积和价值。
输出
输出一个整数,代表可获得的最大价值。
样例输入
5 20
2 3
3 4
10 9
5 2
11 11
样例输出
30
数据规模与约定
时间限制:1s
内存限制:64M
对于100%的数据,1≤N,V≤10000。
题解:
本题与上题几乎一样,除了一点:上一题中每一件物品只有一个,而这一题中每一件物品都有无限个,这其实并不会带来多大的不同,我们还是用上提的思路去思考:选取状态为:dp[i][j]代表前i件物品,选取的总体积最大为j时能获得的最大价值。然后利用容斥原理的思想:将状态整个分成两部分——选取了第i件物品的和没选取第i件物品的。没选的依然是dp[i-1][j],但是选了的不一样。由于这道题每件物品都有无限个,因此我们的表达式应该是:dp[i][j-v[i]]+w[i]。依然是为至少一个物品i留出空位,但若是沿袭上题的表达式,就会变成只选择一个物品i。
代码:
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int dp[2][10005] = { 0 };//前i件物品,选取的总体积最大为j时能获得的最大价值
int w[10005], v[10005];
int main()
{
int V, N;
cin >> N >> V;
for (int i = 1;i <= N;i++)
{
cin >> v[i] >> w[i];
}
for (int i = 1;i <= N;i++)
{
for (int j = 1;j <= V;j++)
{
if (j >= v[i])//背包的空间能放下第i件物品
dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[i % 2][j - v[i]] + w[i]);
else dp[i % 2][j] = dp[(i - 1) % 2][j];
}
}
cout << dp[N % 2][V];
return 0;
}
(3)多重背包
题目描述
给有一个能承重 V 的背包,和n种物品,每种物品的数量有限多,我们用重量、价值和数量的三元组来表示一个物品,第 i 件物品表示为(Vi,Wi,Si),问在背包不超重的情况下,得到物品的最大价值是多少?
输入
第一行输入两个数V、n,分别代表背包的最大承重和物品种类数。
接下来 n 行,每行三个数 Vi、Wi、Si,分别代表第 i 种物品的重量、价值和数量。
输出
输出一个整数,代表在背包不超重情况下所装物品的最大价值。
样例输入1
15 4
4 10 5
3 7 4
12 12 2
9 8 7
样例输出1
37
数据规模与约定
时间限制:1 s
内存限制:64 M
60% 的数据保证(Vi≤V≤1000,n≤100,Si≤10,Wi≤1000)
100% 的数据保证(Vi≤V≤100000,n≤100,Si≤100000,Wi≤1000)
题解:
在我们看完上述两道题之后,会发现这道题,其实可以把它当成是一个01背包的问题:想想看,把每一个物品都当成是一个独立的物品,也就是说,有多个价值和体积都相同的物品。有点像是脑筋急转弯。当然这不是这道题最正确的解法。有关于正确的解法,放在之后的文章中详细说明。