EH's Blog

题目情境#

题目链接:https://www.luogu.com.cn/problem/P1757 ↗

题目描述

自 0101 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 0101 背包,他的物品大致可分为 kk 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。

输入格式

两个数 m,nm,n,表示一共有 nn 件物品,背包能承受的最大重量为 mm。

接下来 nn 行,每行 33 个数 ai,bi,cia_i,b_i,c_i,表示物品的重量,利用价值,所属组数。

输出格式

一个数,最大的利用价值。

输入 #1

45 3
10 10 1
10 5 1
50 400 2
plaintext

输出 #1

10
plaintext

0≤m≤10000 \leq m \leq 1000,1≤n≤10001 \leq n \leq 1000,1≤k≤1001\leq k\leq 100,ai,bi,cia_i, b_i, c_i 在 int 范围内。

算法解析:#

分组背包:每组内最多选一个物品。状态 f[i][j]f[i][j] 表示前 ii 组、容量 jj 的最大价值。对每组枚举选组内哪个物品(或不选):f[i][j]=max⁡(f[i−1][j], max⁡kf[i−1][j−v[k]]+w[k])f[i][j]=\max(f[i-1][j],\ \max_k f[i-1][j-v[k]]+w[k])。可压缩为一维,容量逆序。复杂度 O(n⋅V⋅s)O(n\cdot V\cdot s)。

C++代码实现#

// 分组背包 朴素算法
#include<iostream>
#include<cstring>
using namespace std;

const int N=110;
int v[N][N],w[N][N],s[N];
// v[i,j]:第i组第j个物品的体积 s[i]:第i组物品的个数
int f[N][N];
// f[i,j]:前i组物品,能放入容量为j的背包的最大值

int main(){    
  int n,V; cin>>n>>V;
  for(int i=1;i<=n;i++){
    cin>>s[i];
    for(int j=1;j<=s[i];j++) cin>>v[i][j]>>w[i][j];
  }
  
  for(int i=1;i<=n;i++)     //物品组
  for(int j=1;j<=V;j++)     //体积
  for(int k=0;k<=s[i];k++)  //同组内的物品只能选一个
    if(j>=v[i][k]) f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);                 

  cout<<f[n][V];
}
c
E10 分组背包
https://ehnotgod.site/zh/blog/e10-%E5%88%86%E7%BB%84%E8%83%8C%E5%8C%85
Author EH
Published at August 8, 2026