题目背景
直达通天路·小 A 历险记第二篇
题目描述
自 0101 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 0101 背包,他的物品大致可分为 kk 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。
输入格式
两个数 m,nm,n,表示一共有 nn 件物品,总重量为 mm。
接下来 nn 行,每行 33 个数 ai,bi,ciai,bi,ci,表示物品的重量,利用价值,所属组数。
输出格式
一个数,最大的利用价值。
输入输出样例
输入 #1复制
45 3 10 10 1 10 5 1 50 400 2
输出 #1复制
10
说明/提示
1≤m,n≤10001≤m,n≤1000。
两种写法:
一种是每次先考虑将一个背包计算完,另一个是先考虑将一个物品考虑完
写法1:
从最大的背包容量开始倒着往前,每次尝试所有物品,每次一个背包计算完成后,比如dp[43]结束后,再去计算dp[42],当计算dp[42]的时候,我们已经无需考虑dp[43]了。这样倒着往前,直到计算完所有容量的背包。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define INF 0x3f3f3f3f
#define NUM 100
using namespace std;
int main()
{
int m,n;
int g = 0;
int dp[1001];
memset(dp, 0, sizeof(dp));
vector<int> v[NUM];
vector<int> w[NUM];
scanf("%d%d", &m, &n);
for(int i=0; i<n; i++) {
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
w[c].push_back(a);
v[c].push_back(b);
g = max(g, c);
}
for(int i=0; i<=g; i++) {
for(int j=m; j>=0; j--) {
for(int k=0; k<w[i].size(); k++) {
if(j >= w[i][k])
dp[j] = max(dp[j], dp[j-w[i][k]] + v[i][k]);
}
}
}
printf("%d\n", dp[m]);
return 0;
}
写法2:
我们用temp数组记录上一组数据dp结束后的dp值,然后我们先考虑其中一个物品,将该物品放到所有的背包里面(还是倒着放),计算得出放当前物品后的dp值。当放下一个物品时,我们比较的是当前的dp与temp,因为temp自始至终没有改变过,所以我们这次比较的结果其实是最初的dp数组选择当前物品得到的dp与上一次选择物品后得到的dp值的比较。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define INF 0x3f3f3f3f
#define NUM 100
using namespace std;
int main()
{
int m,n;
int g = 0;
int dp[1001];
int temp[1001];
memset(dp, 0, sizeof(dp));
vector<int> v[NUM];
vector<int> w[NUM];
scanf("%d%d", &m, &n);
for(int i=0; i<n; i++) {
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
w[c].push_back(a);
v[c].push_back(b);
g = max(g, c);
}
for(int i=0; i<=g; i++) {
for(int j=0; j<=m; j++)
temp[j] = dp[j];
for(int k=0; k<w[i].size(); k++) {
for(int j=m; j>=w[i][k]; j--) {
dp[j] = max(dp[j], temp[j-w[i][k]]+v[i][k]);
}
}
}
printf("%d\n", dp[m]);
return 0;
}