注:需先预习01背包再做此题
P1757 通天之分组背包:传送门
题目大意:物品大致可分为 k 组,每组中的物品相互冲突(每组只能用一个),求最大使用价值。
方法一:二维数组
定义数组表示第k组第i个的重量,数组表示第k组第i个的价值,数组表示目前用j个价值的最优解。
动态规划转移方程:
代码如下:
#include<bits/stdc++.h>
using namespace std;
int w[110][1100],v[110][1100],f[11000];
int main(){
int m,n,maxxx = 0;
cin >> m >> n;
for(int i = 1;i <= n;i++){
int a,b,c;
cin >>a>>b>>c;
w[c][++w[c][0]] = a;
v[c][++v[c][0]] = b;
maxxx = max(maxxx,c);//打擂台求最大组数
}
for (int k = 1; k <= maxxx; k++){//枚举组数
for(int j = m;j >= 0;j--){//从大到小防止重复
for(int i = 1;i <= w[k][0];i++){//枚举第k组的第i个数
if(j >= w[k][i]){
f[j]= max(f[j],f[j-w[k][i]]+v[k][i]);
}
}
}
}
cout << f[m];//结果存到了f[m]里
return 0;
}
方法二:结构体
使用结构体的有点就是一目了然,十分清楚。具体看代码。
#include<bits/stdc++.h>
using namespace std;
int dp[1001];
struct stu{
int as[1000],b[1000],x;//as[z]表示该项第z项的物品重量,b[z]表示该项第z项的物品价值,x表示该项有x个元素。
}a[300];
int main(){
int m,n,cmax = -1;
cin >> m >> n;
for(int i = 1;i <= n;i++){
int aa,bb,cc;
cin >> aa>> bb>> cc;
a[cc].x+= 1;
a[cc].as[a[cc].x] = aa,a[cc].b[a[cc].x] = bb;
cmax = max(cmax,cc);//打擂台求最大值。
}
for(int i = 1;i <= cmax;i++){
for(int j = m;j >= 1;j--){
for(int z = 1;z <= a[i].x;z++){
if(j < a[i].as[z]) continue;
dp[j] = max(dp[j],dp[j-a[i].as[z]]+a[i].b[z]);
}
}
}
cout << dp[m];
return 0;
}
方法三:一维数组解
#include<bits/stdc++.h>
using namespace std;
int dp[1001],aa[1001],bb[1001],cc[1001],lsh[1001],lh = 0,c[1001],id[1004][1004],len[1001];
int main(){
int m,n,cmax = -1;
cin >> m >> n;
for(int i = 1;i <= n;i++){
cin >> aa[i]>> bb[i]>> cc[i];
lsh[++lh] = cc[i];
}
sort(lsh+1,lsh+lh+1);//用sort排序(为了偷懒)
lh = unique(1+lsh,lsh+lh+1)-lsh-1;//去重后得到的长度
for(int i = 1;i <= n;i++){
int rd = lower_bound(lsh+1,lsh+lh+1,cc[i])-lsh;//二分查找cc[i]的位置,更快。
c[i] = rd;
cmax = max(cmax,rd);
}
for(int i = 1;i <= n;i++){
id[c[i]][++len[c[i]]] = i;
}
for(int i = 1;i <= cmax;i++){
for(int j = m;j >= 1;j--){
for(int z = 1;z <= len[i];z++){
int t = id[i][z];
if(j < aa[t])continue;
dp[j] = max(dp[j],dp[j-aa[t]]+bb[t]);
}
}
}
cout << dp[m];
return 0;
}
方法四:map解
#include<bits/stdc++.h>
using namespace std;
int dp[1001],aa[1001],bb[1001],cc[1001],lsh[1001],lh = 0,c[1001],id[1004][1004],len[1001];
map <int,int> mp;
int main(){
int m,n,cmax = -1;
cin >> m >> n;
for(int i = 1;i <= n;i++){
cin >> aa[i]>> bb[i]>> cc[i];
if(mp[cc[i]] == 0) mp[cc[i]] = ++lh;
c[i] = mp[cc[i]];
}
for(int i = 1;i <= n;i++){
id[c[i]][++len[c[i]]] = i;
}
for(int i = 1;i <= lh;i++){
for(int j = m;j >= 1;j--){
for(int z = 1;z <= len[i];z++){
int t = id[i][z];
if(j < aa[t])continue;
dp[j] = max(dp[j],dp[j-aa[t]]+bb[t]);
}
}
}
cout << dp[m];
return 0;
}
最后总结一下
不得不说,这其实就是01背包精华版!!(题目有间接表明)需掌握01背包