03多重背包问题

具体内容见背包九讲(3)

相关题目:hdu  1171   2844    1059/poj1014     2191    (没做:poj 2392    poj1276)

hdu 2844

大意:有不同价值的硬币,每种价值硬币有一定数量个。求用这些硬币可以组成的钱的种数是多少。

则判断条件不在是 :if( f[i] < f[i-v] + w) ···  而是 if(f[i] == 0 && f[i - v] != 0) sum++

代码:

//是求可能组成<m的钱数的可能数 
#include<iostream>
#include<string.h>
#define size 100010
using namespace std;
int f[size];
int n,m,sum;
void ZeroOnePack(int v)
{
     for(int i=m;i>=v;i--)
     if(f[i]==0 && f[i-v]!=0)   f[i]=1,sum++; 
}
void MultiplePack(int v,int no)
{
     if(v*no>=m)
     {
          for(int i=v;i<=m;i++) 
          if(f[i]==0 && f[i-v]!=0)   f[i]=1,sum++;
     }
     else 
     {
          int k=1;
          while(k<no)
          { 
             ZeroOnePack(k*v);
             no-=k;
             k*=2;
          }
          ZeroOnePack(no*v);
     }
     
     return;
}
int main()
{
    int  v[110],no[110];
    while(scanf("%d%d",&n,&m)!=EOF && n && m)
    {
         for(int i=0;i<n;i++)  scanf("%d",&v[i]);
         for(int i=0;i<n;i++)  scanf("%d",&no[i]);
         memset(f,0,sizeof(f));
         f[0]=1; sum=0;
         for(int i=0;i<n;i++)
         {
             MultiplePack(v[i],no[i]); 
         } 
         printf("%d\n",sum);
    }
    return 0;
}

hdu 2191 比较朴素的多重背包解法:

#include<iostream>
#include<string.h>
using namespace std;
int f[110];
int v[110],w[110],no[110];
int n,m;
void ZeroOnePack(int v,int w)
{
     for(int i=n;i>=v;i--)
     if(f[i]<f[i-v]+w)  f[i] = f[i-v]+w;
}
void MultiplePack(int v,int w,int no)
{
    if(v*no>=n)
    {
         for(int i=v;i<=n;i++) if(f[i]<f[i-v]+w) f[i] = f[i-v]+w;
    }
    int k=1;
    while(k<no)
    {
        ZeroOnePack(v*k,k*w);
        no-=k;
        k*=2;
    }
    ZeroOnePack(v*no,no*w);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(f,0,sizeof(f));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&v[i],&w[i],&no[i]);
        }  
        for(int i=0;i<m;i++) MultiplePack(v[i],w[i],no[i]); 
         int max=0;
         
        for(int i=n;i>=0;i--)
        if(f[i]>max) max=f[i]; 
        printf("%d\n",max);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值