原题链接
P1757
题目类型:
普
及
−
{\color{orange} 普及-}
普及−
AC记录:Accepted
题目大意
自 01 01 01背包问世之后,小 A A A对此深感兴趣。一天,小 A A A去远游,却发现他的背包不同于 01 01 01背包,他的物品大致可分为 k k k组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。
输入格式
两个数 m , n m,n m,n,表示一共有 n n n件物品,总重量为 m m m。
接下来 n n n行,每行 3 3 3个数 a i , b i , c i a_i,b_i,c_i ai,bi,ci ,表示物品的重量,利用价值,所属组数。
输出格式
一个数,最大的利用价值。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input
45 3
10 10 1
10 5 1
50 400 2
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
10
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
取第一个物品,总价值为10
。
数据范围
对于 100 % 100\% 100%的数据, n , m ≤ 1000 n,m\le 1000 n,m≤1000。
解题思路
题目都告诉你了,
d
p
dp
dp题目啊。
这道题就是分组背包的模板题。
其实吧,分组背包看起来高级,实际上和
01
01
01背包差不多,甚至我都觉得,就是
01
01
01背包的船新版本。
做法就是枚举分出来的每一个组和容量,然后在从一个组里面选出一个物品来进行动态转移,那么动态转移方程也出来了:
设
f
i
,
j
f_{i,j}
fi,j为当背包容量为
j
j
j时,选前
i
i
i组里面的东西的最大价值,
w
i
w_i
wi为第
i
i
i个物品的重量,
c
i
c_i
ci为第
i
i
i个物品的价值,则:
f
i
,
j
=
{
f
i
−
1
,
j
j
<
w
k
,
k
为
第
i
组
里
面
的
物
品
m
a
x
(
f
i
−
1
,
j
,
f
i
−
1
,
j
−
w
k
+
c
k
)
j
≥
w
k
,
k
为
第
i
组
里
面
的
物
品
f_{i,j}=\begin{cases} f_{i-1,j} & j<w_k\ ,\ k为第i组里面的物品 \\ max(f_{i-1,j},f_{i-1,j-w_k}+c_k) & j\ge w_k\ ,\ k为第i组里面的物品 \end{cases}
fi,j={fi−1,jmax(fi−1,j,fi−1,j−wk+ck)j<wk , k为第i组里面的物品j≥wk , k为第i组里面的物品
答案为:
f
k
,
m
,
k
为
组
的
个
数
。
f_{k,m}\ ,\ k为组的个数。
fk,m , k为组的个数。
优化
从上面的状态转移方程可以看出,
f
i
,
j
f_{i,j}
fi,j只和
f
i
−
1
f_{i-1}
fi−1里面的元素有关系,所以我们可以省去
i
i
i那一维,直接写成
f
j
f_j
fj的形式。则动态转移方程变成:
f
j
=
{
f
j
j
<
w
k
,
k
为
第
i
组
里
面
的
物
品
m
a
x
(
f
j
,
f
j
−
w
k
+
c
k
)
j
≥
w
k
,
k
为
第
i
组
里
面
的
物
品
f_{j}=\begin{cases} f_{j} & j<w_k\ ,\ k为第i组里面的物品 \\ max(f_{j},f_{j-w_k}+c_k) & j\ge w_k\ ,\ k为第i组里面的物品 \end{cases}
fj={fjmax(fj,fj−wk+ck)j<wk , k为第i组里面的物品j≥wk , k为第i组里面的物品
答案为:
f
m
f_{m}
fm
最后还要注意一点:洛谷上面的组数不是按照 1 ⋯ n 1\cdots n 1⋯n的顺序给出的,所以在做题时要注意处理好。
最后,祝大家早日
上代码
#include<iostream>
#include<vector>
#include<map>
using namespace std;
struct obj{
obj(int a=0,int b=0):w(a),c(b){}
int w,c;
};
vector<vector<obj> > a;
map<int,int> change;
vector<int> f;
vector<obj> emp1;
int v,n,t,pos;
int main()
{
cin>>v>>n;
f.assign(v+10,0);
a.push_back(emp1);
for(int i=1; i<=n; i++)
{
int x,y,z;
cin>>x>>y>>z;
if(change[z]==0)
{
change[z]=++pos;
a.push_back(emp1);
}
a[change[z]].push_back(obj(x,y));
}
for(int i=1; i<=pos; i++)
for(int j=v; j>=0; j--)
for(int k=0; k<a[i].size(); k++)
{
if(a[i][k].w>j)
continue;
else
f[j]=max(f[j],f[j-a[i][k].w]+a[i][k].c);
}
cout<<f[v]<<endl;
return 0;
}
完美切题 ∼ \sim ∼