上次我们讲了二维费用的背包问题与混合背包问题,今天,我们来介绍一下喜欢 打架 的背包问题——分组背包问题。
分组背包问题
最初始的问题
例【n+n】一个旅行者有一个容量为V的超级背包。现在有n件物品,他们有各自的重量,他们也有各自对应的价值。这些物品被划分为若干组,每个组的每个物品之间都有矛盾,所以,为了让他们 打架 不打架,所以每组只能派出一位“代表”进入背包。请问,能装下的最大价值是多少?
诶哟喂,这物品都开始打架了,这年头······
算法分析
这个问题呢,就把原来的01背包问题分组成了在每个组里头都有n种选择。例如:
此时,这个组里有多少个物品就有多少种在组内选择1件物品的方法。根据这个思路,我们发现,在每一个组里面都有(物品数)+1种选择的方法,那个+1就指的是不选择的情况。于是,我们设f[k][v] 表示前k组物品使费用剩下v能取得的最大价值,则,列出方程:
f
(
k
)
(
v
)
=
m
a
x
(
f
(
k
−
1
)
(
v
)
,
f
(
k
−
1
)
(
v
−
w
(
i
)
)
+
c
(
i
)
∣
i
∈
k
)
f(k)(v)=max(f(k-1)(v),f(k-1)(v-w(i))+c(i)|i\in k)
f(k)(v)=max(f(k−1)(v),f(k−1)(v−w(i))+c(i)∣i∈k)
于是,我们想想,如何满足物品i属于第k组这个条件。这时候,我们想到了在最里层与最外层修改for循环,即可满足条件。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int f[5000],c[5000],w[5000],a[5000][5000],i,j,n,m,s,k,t,p;
int main ()
{
cin>>n>>m>>t;
for (i=1; i<=m; i++)
{
cin>>w[i];
cin>>c[i];
cin>>p;
a[p][0]++;
a[p][a[p][0]]=i;
}
for (k=1; k<=t; k++)
for (i=n; i>=0; i--)
for (j=1; j<=a[k][0]; j++)
if (i>=w[a[k][j]])
f[i]=max(f[i],f[i-w[a[k][j]]]+c[a[k][j]]);
cout<<f[n];
return 0;
}
啊,这么简单?????只有打五个?才可以理解我的疯狂!
今天稍微写短一点,希望大家多多支持点赞!
今天超级 小 大福利
分组背包问题的测试数据点!来一波!
178 26 4
43 1527 3
130 1077 1
74 527 2
155 74 3
157 186 3
144 1796 2
159 727 3
129 929 3
47 338 1
17 1302 1
133 1725 2
124 1998 1
125 1332 2
162 207 3
21 583 3
137 613 1
163 126 2
98 1858 2
140 553 1
152 395 3
34 580 1
40 555 1
66 333 3
38 1594 3
173 1840 1
99 1186 1
4754
测测你的程序,加油哦!