1 题面
1.1 描述
一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,…,Wn,他们的价值分别为C1,C2,…,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件,求:将那些物品装如背包可使这些物品的费用总和不超过背包的容量,且价值最大
1.2 输入
第1行:三个整数,V,N,T(V<=200,N<=30,T<=10) 第2行到N+1行:每行3个整数Wi,Ci,P,表示每个物品的重量,价值,组号
1.3 输出
一个数,表示最大总价值
1.4 样例
输入
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
输出
20
1.5 来源
石室联中WOJ
2 分析
裸的板子题
考虑如何做到每个组中最多选一个,当然是按组处理
也就是说第一层循环是对组的循环
再考虑如何限制“最多选一个”,我们来看一般的转移方程:
i
f
(
v
≥
w
i
)
f
v
=
m
a
x
(
f
v
,
f
v
−
w
i
+
c
i
)
if(v\geq w_i)f_v=max(f_v,f_{v-w_i}+c_i)
if(v≥wi)fv=max(fv,fv−wi+ci)
考虑到最多选一个,所以采用"01背包"的做法,倒着枚举
v
v
v
若是先循环
i
i
i,再循环
v
v
v,则循环中后面的
i
i
i会用到前面
i
i
i的结果
举个例子,假设某组中分别为
[
1
,
2
]
,
[
2
,
3
]
[1,2],[2,3]
[1,2],[2,3](形式为
[
w
i
,
c
i
]
[w_i,c_i]
[wi,ci]),
V
=
3
V=3
V=3
先对
i
=
1
i=1
i=1来一次循环,
f
=
[
0
,
2
,
2
,
2
]
f=[0,2,2,2]
f=[0,2,2,2]
再对
i
=
2
i=2
i=2来一次,
f
=
[
0
,
2
,
3
,
5
]
f=[0,2,3,5]
f=[0,2,3,5]
答案为
f
3
=
5
f_3=5
f3=5
那么问题来了,真的能取到
5
5
5么?显然不能,因为1和2不能同时取
而这个5的来源便是因为对
i
=
2
i=2
i=2进行循环时,
f
3
−
2
=
f
1
=
2
f_{3-2}=f_1=2
f3−2=f1=2这个结果是通过取1得到的,而此处再取2便得到了5。显然这与题意“每组最多取一个”不符
所以先循环
v
v
v,再循环
i
i
i,这样就保证对每个
i
i
i,算出的结果不会用来和另一个同组的
i
i
i取
m
a
x
max
max。举个例子(数据同上)
v
=
3
,
f
=
[
0
,
0
,
0
,
0
]
v=3,f=[0,0,0,0]
v=3,f=[0,0,0,0]
v
=
2
,
f
=
[
0
,
0
,
3
,
0
]
v=2,f=[0,0,3,0]
v=2,f=[0,0,3,0]
v
=
1
,
f
=
[
0
,
2
,
3
,
0
]
v=1,f=[0,2,3,0]
v=1,f=[0,2,3,0]
v
=
0
,
f
=
[
0
,
2
,
3
,
0
]
v=0,f=[0,2,3,0]
v=0,f=[0,2,3,0]
∴
a
n
s
=
0
\therefore ans=0
∴ans=0
3 代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch;bool flag=0;
while(!isdigit(ch=getchar()))if(ch=='-')flag=1;
for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
if(flag)n=-n;
}
const int MAXV = 205;
const int MAXN = 35;
const int MAXT = 15;
int V, n, K;
int Group[MAXT][MAXN], num[MAXT];
int f[MAXV], w[MAXN], c[MAXN], p[MAXN];
int main(){
Read(V); Read(n); Read(K);
for(register int i=1; i<=n; i++){
Read(w[i]); Read(c[i]); Read(p[i]);
Group[p[i]][++num[p[i]]] = i;
}
for(register int i=1; i<=K; i++)
for(register int j=V; j>=0; j--)
for(register int k=1; k<=num[i]; k++){
int now=Group[i][k];
if(j >= w[now])
f[j] = max(f[j], f[j-w[now]]+c[now]);
}
cout<<f[V]<<endl;
return 0;
}