首先,如果对01背包不理解的同学请移步 http://blog.csdn.net/sm9sun/article/details/53235986
理解了01背包之后,我们来说明一下多重背包,多重背包就是一个物品有m个,即对于单个物品来说,他的取舍
不再是0,1.而可能是0,1,2,3,4……那么问题看起来就复杂的多。
我们看一下01背包的循环
for(i=1;i<=n;i++) //外层循环物品个数
{
for(j=0;j<=v;j++) //内层循环每个容量点
{
if(j-b[i]>=0)
dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-b[i]]+a[i]); //容量大于该物品体积时状态转移方程
else
dp[i][j]=dp[i-1][j]; //容量小于该物品体积,只能舍弃
}
}
那么想要实现单个物品n[i]多种选择的话,首先必须要在外层循环里再加一层循环,来遍历所取物品的个数
例如:
for(i=1;i<=n;i++) //外层循环物品个数
{
for(k=0;k<=[c][i];k++) //假设C[i]是物品i的数量
{
for(j=0;j<=v;j++) //内层循环每个容量点
{
if(j-b[i]*k>=0)
dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-b[i]*k]+a[i]*k); //取k个物品
else
dp[i][j]=dp[i-1][j]; //容量小于该物品体积,只能舍弃
}
}
}
假设 大概是这样的,应该是能够实现~并且也不用考虑时间复杂度,因为c[i]是根据不同物品个数而定,我们仔细分析一下,发现i循环,k循环是在干一件事,
其实就是遍历物品,只不过k进一步的说明这个物品取舍情况。如果单个物品i的k值很大,比如10000,那么也就在当前i值走10000次循环而已,当i改变后,下一次k循环
可能又只是走1次,2次。
那么我们完全可以换一种更简单的思路,既然我还是遍历了所有物品,我们不如将其合并。如果i物品有k个,那么我就索性认为有k个物品,其体积、价值完全等价与i
这样就等同于01背包问题了。
假设物品i有k个,其体积为v,价值为p,即
while(i.k--)
{
count++;
V[count]=i.v;
P[count]=i.p;
}
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2191
题目描述:每袋大米都含有重量、价值、袋数,即多重背包问题。
#include<stdio.h>int fmax(int a,int b){return a>b?a:b;}int dp[2100][110];int main(){ int i,j,c,v,n; int a[2100],b[2100]; int x,y,z,count; scanf("%d",&c); while(c--) { count=0; scanf("%d%d",&v,&n); while(n--) //把多重背包分开存 { scanf("%d%d%d",&x,&y,&z); while(z--) { count++; b[count]=x; a[count]=y; } } for(i=1;i<=count;i++) { for(j=0;j<=v;j++) { if(j>=b[i]) dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-b[i]]+a[i]); else dp[i][j]=dp[i-1][j]; } }/* for(i=0;i<=count;i++) { for(j=0;j<=v;j++) { printf("%6d ",dp[i][j]); } printf("\n"); }*/ printf("%d\n",dp[count][v]); } return 0;}