poj 1014 ,hdu 2844 (多重背包)

poj 1014
题意:给出6个数,分别表示面值为1-6对应钱币的数量。判断是否可以等值分割总金额。


分析:多重背包应用。计算出总金额sum,若为奇数,则false,否则sum/=2;背包容量即为此时的sum,费用和价值相同,求出dp[sum].判断dp[sum]==sum?true:false.
注意点:因为物品要装满背包,所以初始化dp数组,dp[1……n]=负无穷,dp【0】=0;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define NN 20000*6
#define INF_MIN -0xfffff
const int l=6;
#define loop(i,k,n) for(i=k;i<=n;i++)
int dp[NN],num[8],va[]={0,1,2,3,4,5,6};

void ZeroOne_Package(int value,int weight,int m)
{
    for(int j=m;j>=weight;j--)
        dp[j]=max(dp[j],dp[j-weight]+value);
}

void Complete_Package(int value,int weight,int m)
{
    for(int j=weight;j<=m;j++)
    dp[j]=max(dp[j],dp[j-weight]+value);
}

void Multiply_Package(int *v,int *w,int m,int n)
{
    for(int i=1;i<=n;i++){
        if(num[i]*w[i]>m)
            Complete_Package(v[i],w[i],m);
        else{
            int k=1;
            while(k<=num[i])
            {
                ZeroOne_Package(k*v[i],k*w[i],m);
                num[i]-=k;
                k<<=1;
            }
            ZeroOne_Package(num[i]*v[i],num[i]*w[i],m);
        }
    }
}
int main()
{
    int i,k=1;
    while(k)
    {
        int sum=0,flag=0;
        loop(i,1,6)
            scanf("%d",num+i),sum+=i*num[i],flag|=num[i];
        if(!flag)
            break;
        printf("Collection #%d:\n",k++);
        if(sum&1)
            puts("Can't be divided.\n");
        else{
            sum>>=1;
            loop(i,1,sum)
                dp[i]=INF_MIN;  dp[0]=0;
            Multiply_Package(va,va,sum,l);
            //printf("dp[sum]= %d\n",dp[sum]);
            if(dp[sum]!=sum)
                puts("Can't be divided.\n");
            else
                puts("Can be divided.\n");
        }
    }
    return 0;
}

hdu 2844
题意 : n种钱币,金额cash .给出每种金币的数量及其面值 ,求不超过cash的可以价值 数。
分析:多重背包,和上面一题一样,没啥区别,同一模板=_=

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define  NN  100000+2
int dp[NN],num[1002],va[102];
#define loop(i,k,n) for(i=k;i<=n;i++)
#define loop2(i,k,n) for(i=n;i>=k;i--)
const int INF_MIN=-0xffffff;
void Zero(int v,int w,int m)
{
    int j;
    loop2(j,w,m)
        dp[j]=max(dp[j],dp[j-w]+v);
}
void Complete(int v,int w,int m)
{
    int j;
    loop(j,w,m)
        dp[j]=max(dp[j],dp[j-w]+v);
}
void Multiply(int *v,int *w,int m,int n)
{
    int i,j,k;
    loop(i,1,n)
    {
        if(num[i]*w[i]>m)
            Complete(v[i],w[i],m);
        else{
            k=1;
            while(k<=num[i]){
                Zero(k*v[i],k*w[i],m);
                num[i]-=k;
                k<<=1;
            }
            Zero(num[i]*v[i],num[i]*w[i],m);
        }
    }
}
int main()
{
    int n,m,i;
    while(scanf("%d%d",&n,&m),n&&m)
    {
        int Count=0;
        loop(i,1,n)     scanf("%d",va+i);
        loop(i,1,n)     scanf("%d",num+i);
        loop(i,1,m)     dp[i]=INF_MIN;
        dp[0]=0;
        Multiply(va,va,m,n);
        loop(i,1,m)
        if(dp[i]==i)
            Count++;
        printf("%d\n",Count);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值