代码改变世界

HDU--2844 Coins(多重背包)

2013-12-04 17:00  gongti  阅读(175)  评论(0)    收藏  举报
题目http://acm.hdu.edu.cn/showproblem.php?pid=2844

题目分析 给定N和M,N表示硬币的种类,M表示最大不超过的总价值,
相当于背包的重量或体积等一类的限制条件。A[1....N]表示硬币的面值
C[1....N]表示相应的硬币的数目。
求能用这些硬币组合成多少种金额(金额在1~M之间)?
转换为背包问题就是1~M中间的数值能否可以被组成。通常所做的背包是
求最大值是那种金额?这里我们如果可以到某一个值i那么令dp[i]=1表示可以取到。
#include<stdio.h>

int M,dp[100001];

//O1背包
void ZeroOnePack(int c,int w)
{
  for(int i=M;i>=c;i--)
    dp[i]=dp[i]|dp[i-c];
}
//完全背包
void CompletePack(int c,int w)
{
  for(int i=c;i<=M;i++)
    dp[i]=dp[i]|dp[i-c];
}
//多重背包
void MultiplePack(int c,int w,int n)
{
  if(c*n>=M)
  {
    CompletePack(c,w);
    return;
  }
  int k=1;
  while (k<=n)
  {
    ZeroOnePack(k*c,k*w);
    n-=k;
    k*=2;
  }
  ZeroOnePack(n*c,n*w);
}

int main()
{
  int N,a[101],c[101];
  while (scanf("%d%d",&N,&M)!=EOF)
  {
    if(!N&&!M) break;
    for(int i=1;i<=N;i++)
      scanf("%d",&a[i]);
    for(int i=1;i<=N;i++)
      scanf("%d",&c[i]);
      
    //初始化需要注意,dp[0]表示一种方案满足金额为0  dp[1...M]初始化为没有方案满足
    //这里的dp[i]表示根据是否又满足金额为i 是为1 否为0
    for(int i=0;i<=M;i++)
      dp[i]=0;
    dp[0]=1;

    for(int i=1;i<=N;i++)
      MultiplePack(a[i],a[i],c[i]);

    int sum=0;
    for(int i=1;i<=M;i++)
      sum+=dp[i];

    printf("%d\n",sum);
  }
  return 0;
}