题目背景
直达通天路·小 A 历险记第二篇
题目描述
自 0101 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。
输入格式
两个数 m,n,表示一共有 n 件物品,总重量为 m。
接下来 n 行,每行 3个数 ai,bi,ci,表示物品的重量,利用价值,所属组数。
输出格式
一个数,最大的利用价值。
输入输出样例
输入 #1复制
45 3 10 10 1 10 5 1 50 400 2
输出 #1复制
10
说明/提示
1≤m,n≤1000。
思路
开始的思路是,既然每组的物品互斥,那么每组物品就只保留容积最小或者价值最大的,最后再利用01背包的思路即可。但是,实际上这种做法并不严谨...。但是却AC了,就懒得管了......
Code
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m,vans,wans,kmax;
struct nod{
int w,v,k;
};
nod t;
int dp[N];
int v[N];//价值
int w[N];//体积
int main(){
scanf("%d%d",&m,&n);
fill(w+1,w+1+n,99999);
wans=m;//总重量
for(int i=1;i<=n;i++){
scanf("%d%d%d",&t.w,&t.v,&t.k);
kmax=max(t.k,kmax);
if(t.w<=m&&t.v>v[t.k]||t.w<w[t.k]) {//每组只保留价值最大的或者空间最小的
v[t.k]=t.v;
w[t.k]=t.w;
}
}
for(int i=1;i<=kmax;i++){
for(int j=m;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
printf("%d",dp[m]);
return 0;
}
再一个思路就是直接分组进行01背包枚举
Code
#include<bits/stdc++.h>
using namespace std;
int v,n,t;
int x;
int g[205][205];
int i,j,k;
int w[10001],z[10001];
int b[10001];
int dp[10001];
int main(){
cin>>v>>n;
for(i=1;i<=n;i++){
cin>>w[i]>>z[i]>>x;
t=max(t,x);//找到最大组数
b[x]++;//相应组数的物品数量++
g[x][b[x]]=i;//记录第x组第b[x]个物品的下标为i
}
for(i=1;i<=t;i++){//枚举组
for(j=v;j>=0;j--){//枚举体积
for(k=1;k<=b[i];k++){//每组每一组的所有物品
if(j>=w[g[i][k]]){//如果物品的容量合法
dp[j]=max(dp[j],dp[j-w[g[i][k]]]+z[g[i][k]]);//那就更新
}
}
}
}
cout<<dp[v];
return 0;