内容见: 背包九讲
相关题目:hdu 1712 3033 3535(各种分组背包)
hdu 1712
代码:
#include<iostream>
#include<string.h>
using namespace std;
int f[110];
int w[110][110];
int n,m;
void GroupPack()
{
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
for(int k=1;k<=m;k++)
{
if(f[j]<f[j-k]+w[i][k]&&j>=k) //j>k这个判断必不可少!!!防止当前所用空间大于背包容量
f[j]=f[j-k]+w[i][k];
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF &&n &&m)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) scanf("%d",&w[i][j]);
}
memset(f,0,sizeof(f));
GroupPack();
printf("%d\n",f[m]);
}
return 0;
}
hdu 3033
如果①、②两个循环的顺序改变的话,一定会出错!!!
例如测试数据中第一种品牌有两种产品: 4 - 6 、5 - 77 ,假设m = 300
若是:for t = 0------>len
for j = m ----->0
则第一次循环: f [ i ] [ 300~4] = 6;
第二次循环 : max { f [ i ] [ 300 ] 、f [ i ] [300 - 55] +77 } = f[ i ] [ 300 ] = 77+6;
若是:for j = m ------> 0
for t = 0 ------->len
则t=0: f [ i ] [ 300 ] = 6;
t = 1时: f[ i ] [300] = max { f[ i ] [ 300 ]、f[ i ] [300 - 55]+ 77 =77(因为之前只有f [i][300]被赋了值) } = 77;
所以第二种循环顺序将会覆盖原来较小的值,而不是“累加”,故而产生错误!
判断取值时:
f[i][j]=max(f[i][j],f[i][j-v[i][t]]+w[i][t]); 是判断该组中该种产品是取还是不取
f[i][j]=max(f[i][j],f[i-1][j-v[i][t]]+w[i][t]); // 是在之前i-1组的最值下取一个该组产品(f[i-1][j-v]+w),和该组
// 产品最值情况进行比较,则f[i-1][j-v]+w保证了一定取该组中的一个产品
代码:
#include<iostream>
#include<string.h>
using namespace std;
int f[11][10010];
int v[11][1010],w[11][110],len[11];
int n,m,k;
int max(int a, int b)
{
if(a>b) return a;
else return b;
}
void _GroupPack()
{
for(int i=1;i<=k;i++)
{
for(int t=0;t<=len[i];t++)
{
for(int j=m;j>=0;j--)//如果将这层与上一层循环换位,则会出现错误
//f[i][j] = f[i][j-v]+w将会改变f[i][j]
{
if(j>=v[i][t])
{
f[i][j]=max(f[i][j],f[i][j-v[i][t]]+w[i][t]);
f[i][j]=max(f[i][j],f[i-1][j-v[i][t]]+w[i][t]);
}
}
}
}
}
int main()
{
int a,b,c;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(len,-1,sizeof(len));
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a,&b,&c);
v[a][++len[a]]=b; w[a][len[a]]=c;
}
memset(f,0,sizeof(f));
_GroupPack();
int ans=0;
for(int i=m;i>=0;i--)
{
if(f[k][i]>ans) ans=f[k][i];
}
if(ans)
printf("%d\n",ans);
else printf("Impossible\n");
}
return 0;
}