题目链接 https://ac.nowcoder.com/acm/contest/58860
分组背包问题
有
N
N
N 组物品和一个容量是
V
V
V 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是
v
i
j
v_{ij}
vij,价值是
w
i
j
w_{ij}
wij,其中
i
i
i 是组号,
j
j
j 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数
N
N
N,
V
V
V,用空格隔开,分别表示物品组数和背包容量。
接下来有
N
N
N 组数据:
- 每组数据第一行有一个整数 S i S_i Si , 表示第 i 个物品组的物品数量;
- 每组数据接下来又 S i S_i Si 行 , 每行有两个整数 v i j v_{ij} vij , w i , j w_{i,j} wi,j ,用空格隔开,分别表示第 i i i 个物品组的第 j j j 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
#include<bits/stdc++.h>
using namespace std;
int f[101];
vector<int> v[101],w[101];
int main()
{
int n,m;cin>>n>>m;
for(int i=0;i<n;i++)
{
int s;cin>>s;
for(int j=0;j<s;j++)
{
int vv,ww;cin>>vv>>ww;
v[i].push_back(vv);
w[i].push_back(ww);
}
}
for(int i=0;i<n;i++)
for(int j=m;j>=0;j--)
for(int k=0;k<v[i].size();k++)
if(j>=v[i][k])
f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
cout<<f[m];
return 0;
}
M - 二手物品回收
- 这道题是一个背包问题,严格上来说是一个分组背包问题,当前有 M M M 组,将当前每组取部分商品的最大利润是多少,但是第一次取商品时需要付一定的邮费。
- 我们可以这样考虑,将每个商品的价值从大到小排序,然后将一个商品的价值减去邮费,这样取前几个就是最优的解。
- 由于分组背包是每组选择一个物品,所以我们要考虑如何转化成分组背包问题。将排完序之后商店的商品做一个前缀和,对于第 k k k 个物品我们就可以理解为选取前 k k k 个商品的选法,所以这样就可以求出最优解。
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> g[N];
int x[N],sum[N][N];
int dp[N];
int main()
{
int n,m,k;cin>>n>>m>>k;
for(int i=1;i<=m;i++) cin>>x[i];
for(int i=1;i<=n;i++)
{
int a,b;cin>>a>>b;
g[b].push_back(a);
}
for(int i=1;i<=m;i++)
{
if(g[i].empty()) continue;
sort(g[i].begin(),g[i].end());
reverse(g[i].begin(),g[i].end());
g[i][0]-=x[i];
}
for(int i=1;i<=m;i++)
for(int j=1;j<=g[i].size();j++)
sum[i][j]+=sum[i][j-1]+g[i][j-1];
memset(dp,-0x3f,sizeof dp);
dp[0]=0;
for(int i=1;i<=m;i++)
for(int j=k;j>=0;j--)
for(int c=0;c<=g[i].size();c++)
if(j>=c)
dp[j]=max(dp[j],dp[j-c]+sum[i][c]);
cout<<dp[k];
return 0;
}