为了账号安全,请及时绑定邮箱和手机立即绑定

背包——多重背包(hdu2191)

标签:
算法

首先,如果对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;}


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消