内容见: 背包九讲
相关题目: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; }