码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)

时间:2015-08-18 15:45:04      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:

题意:给出经费的最大值n,再给出   种类m和每种的袋数c、价格p、重量h,求能买大米的最大重量

思路:每种物品有一个固定的次数上限。为多重背包问题。转换为01背包来做

以下方法,均为转化为01背包来做

思路1:物品不摊开,选取每一种时,进行讨论,(相当于竖着填背包v的一列,一列一列的填

码1:kj

技术分享
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110];
int main()
{
    int i,j,k,tem;
    int t,n,_v;//测试用例个数,物品种类,背包大小
    int c[110],v[110];//花费,价值
    int num[110];//每种物品个数
    int tc,tv;//拆分时物品花费,价值
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&_v,&n);
        memset(dp,0,sizeof(dp));

        for(i=1; i<=n; ++i)scanf("%d%d%d",&c[i],&v[i],&num[i]);
        //////
        for(i=1; i<=n; ++i)
            for(k=_v; k>=c[i]; --k)
                for(j=1; j<=num[i]&&j*c[i]<=k; ++j)//此处比01背包多了一层循环
                {
                    tc=j*c[i];
                    tv=j*v[i];
                    tem=dp[k-tc]+tv;
                    if(tem>dp[k])dp[k]=tem;
                }
        //
        printf("%d\n",dp[_v]);
    }
    return 0;
}
View Code


思路2:物品摊开,然后处理01背包(相当于横着填物品的一行,一行一行的填

2.1朴素拆分,把每种物品展开,既有n件a物品,则进行n件是否选取操作

码2:jk

技术分享
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110];
int main()
{
    int i,j,k,tem;
    int t,n,_v;//测试用例个数,物品种类,背包大小
    int c[110],v[110];//花费,价值
    int num[110];//每种物品个数
    int tc,tv;//拆分时物品花费,价值
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&_v,&n);
        memset(dp,0,sizeof(dp));

        for(i=1; i<=n; ++i)scanf("%d%d%d",&c[i],&v[i],&num[i]);
        //////
        for(i=1; i<=n; ++i)
            for(j=1; j<=num[i]&&j*c[i]<=_v; ++j)//此处比01背包多了一层循环
                for(k=_v; k>=j*c[i]; --k)
                {
                    tem=dp[k-c[i]]+v[i];
                    if(tem>dp[k])dp[k]=tem;
                }
        //
        printf("%d\n",dp[_v]);
    }
    return 0;
}
View Code


hint:2.1代码与思路1 代码 只是循环次序不一样而已,实际是一样的操作。(并且时间复杂度相同,略麻烦。
因为
思路1:
for(k=_v; k>=c[i]; --k)
      for(j=1; j<=num[i]&&j*c[i]<=k; ++j)
思路2:
for(j=1; j<=num[i]&&j*c[i]<=_v; ++j)
      for(k=_v; k>=j*c[i]; --k)

大体看一下这俩循环,
  c[i]   k             _v
  ----------------------
1 |  .   .   .   .    . |
  |      .   .   .    . |
j |          .   .    . |
  |              .    . |
m |                   . |
  ---------------------()

这两个循环做的循环次数是相同的,都是矩阵中  ‘.‘的部分,也就是说,计算次数相同,时间复杂度相同


2.2  二进制拆分,有n件a物品,则拆成 1,2,4,8,...,q 这样,即 1+2+4+...+q=n

码3:

技术分享
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110];
int main()
{
    int i,j,k,tem;
    int t,n,_v;//测试用例个数,物品种类,背包大小
    int c[110],v[110];//花费,价值
    int num[110];//每种物品个数
    int tc,tv;//拆分时物品花费,价值
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&_v,&n);
        memset(dp,0,sizeof(dp));

        for(i=1; i<=n; ++i)scanf("%d%d%d",&c[i],&v[i],&num[i]);
        //////
        for(i=1; i<=n; ++i)
        {
            for(j=1; j<=num[i]; num[i]=num[i]-j,j=j*2)//此处比01背包多了一层循环
            {
                tc=j*c[i];//拆分后物品花费
                tv=j*v[i];//
                for(k=_v; k>=tc; --k)
                {
                    tem=dp[k-tc]+tv;
                    if(tem>dp[k])dp[k]=tem;
                }
            }
            if(num[i]>0) //如果还有物品,num[i] 即相当于 1+2+4+...+q  中的 q
            {
                tc=num[i]*c[i];
                tv=num[i]*v[i];
                for(k=_v; k>=tc; --k)
                {
                    tem=dp[k-tc]+tv;
                    if(tem>dp[k])dp[k]=tem;
                }
            }
        }
    //
        printf("%d\n",dp[_v]);
    }
    return 0;
}
View Code

 

hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)

标签:

原文地址:http://www.cnblogs.com/bofengyu/p/4739310.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!