背包学习————多重背包背包

有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

状态转移方程:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

此时他面临的不是01背包的选与不选的问题,而是从n[i]里面选多少个的问题。

实现方法:

http://acm.hdu.edu.cn/showproblem.php?pid=2191

1:转化成01背包,将每种背包转换成数量为n[i]的01背包求解

View Code
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 107
#define inf 9999999
int c[N],w[N],f[N],b[N];
int max(int x,int y)
{
return x>y? x:y;
}
int main()
{
int t,i,j,n,m,k;
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
scanf("%d%d%d",&c[i],&w[i],&b[i]);
for(i=0;i<m;i++)
{
for(k=0;k<b[i];k++)
{
for(j=n;j>=c[i];j--)
{
f[j]=max(f[j],f[j-c[i]]+w[i]);
}
}
}
printf("%d\n",f[n]);
}
return 0;
}

 

2:利用二进制的思想(思考中,给出代码实现,原理不理解。。)

View Code
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int max_s = 1007;
int c[max_s],w[max_s],b[max_s],f[max_s];
void zb(int c,int w,int n)
{
for(int i=n;i>=c;i--)
f[i]=max(f[i],f[i-c]+w);
}
void cb(int c,int w,int n)
{
for(int i=c;i<=n;i++)
{
f[i]=max(f[i],f[i-c]+w);
}
}
int main()
{
int t,i,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
scanf("%d%d%d",&c[i],&w[i],&b[i]);
memset(f,0,sizeof(f));
for(i=0;i<m;i++)
{
if(c[i]*b[i]>n)
cb(c[i],w[i],n);
else
{
int k=1;
while(k<b[i])
{
zb(k*c[i],k*w[i],n);
b[i]-=k;
k*=2;
}
zb(b[i]*c[i],b[i]*w[i],n);
}
}
printf("%d\n",f[n]);
}
return 0;
}

3:o(n*v)

http://poj.org/problem?id=1742

View Code
#include <cstdio>
#include <iostream>
using namespace std;
const int max_s = 107;
int f[100007],w[max_s],b[max_s];
//f[i]来表示当前i价格是否出现过,
int sum[100007];//当价格达到i时,最多使用这一种硬币的次数
int main()
{
int n,V,i,j;
while(scanf("%d%d",&n,&V),n+V)
{
int ans=0;
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++)
scanf("%d",&b[i]);
for(i=f[0]=1;i<=V;i++) f[i]=0;
for(i=0;i<n;i++)
{
for(j=0;j<=V;j++) sum[j]=0;//关键是用sum来限定了次数
for(j=w[i];j<=V;j++)//从w[i]到V循环检查看是否能够出现前边没有出现的价格
{
if(!f[j]&&f[j-w[i]]&&sum[j-w[i]]<b[i])
//如果j价格没有出现过,且j-w[i]出现过,并且使用i硬币的次数没有超出给定的数量
{
f[j]=1;//标记为已出现过
sum[j]=sum[j-w[i]]+1;//使用次数+1
ans++;//满足条件++
}
}
}
cout<<ans<<endl;
}
}



posted @ 2011-12-06 17:24  E_star  阅读(306)  评论(0编辑  收藏  举报