多重背包

这篇博客探讨了多重背包问题在编程中的应用,通过两个具体的题目实例——'Coins'和'Dividing',阐述了如何利用多重背包模板和二进制优化方法来解决这类问题。在'Coins'题目中,求解的是在限制硬币类型和数量的情况下,能组成多少种不超过特定价值的组合。而在'Dividing'题目中,重点是判断是否能将不同面值的硬币平均分成两部分。博客指出,当硬币总价值的二分之一为整数时,可以判断能否成功划分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

解析:

多重背包模板题

ac:

#include<bits/stdc++.h>
#define MAXN 105
#define inf 0x3f3f3f
#define M 1000005
using namespace std;
int p[MAXN],v[MAXN],num[MAXN];
int dp[M];

void onepack(int m,int v,int w)
{
    for(int i=m;i>=v;i--)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void compack(int m,int v,int w)
{
    for(int i=v;i<=m;i++)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void multpack(int m,int v,int w,int num)
{
    if(v*num>=m)
    {
        compack(m,v,w);
        return ;
    }
    int k=1;
    for(k=1;k<=num;k<<=1)
    {
        onepack(m,k*v,k*w);
        num=num-k;
    }
    if(num)
        onepack(m,num*v,num*w);
}

int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&v[i],&p[i],&num[i]);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
            multpack(n,v[i],p[i],num[i]);//钱,体积,价值,数目
        printf("%d\n",dp[n]);
    }
    return 0;
}

 Coins

题意:

给n钟硬币,面值为a[i],数目为c[i]

问可以组成的多少种价值不超过m的情况

解析:

多重背包模板题

多重背包+二进制优化

ac:

#include<bits/stdc++.h>
#define inf 0x3f3f3f
#define MAXN 100005
using namespace std;
int a[MAXN],c[MAXN];
int dp[MAXN];

void onepack(int m,int v,int w)
{
    for(int i=m;i>=v;i--)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void compack(int m,int v,int w)
{
    for(int i=v;i<=m;i++)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void multpack(int m,int v,int w,int num)
{
    if(v*num>=m)
    {
        compack(m,v,w);
        return ;
    }
    int k=1;
    for(k=1;k<=num;k<<=1)
    {
        onepack(m,k*v,k*w);
        num=num-k;
    }
    if(num)
        onepack(m,num*v,num*w);
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&c[i]);
        for(int i=0;i<=m;i++)
            dp[i]=-inf;
        dp[0]=0;
        for(int i=0;i<n;i++)
            multpack(m,a[i],a[i],c[i]);
        int sum=0;
        for(int i=1;i<=m;i++)
              if(dp[i]>0)
                sum++;
        printf("%d\n",sum);
    }
    return 0;
}

Dividing

题意:

给6个数,分别代表面值1,2,3,4,5,6硬币的数目

问能否将这些硬币分层相等的两部分.

解析:

多重背包+二进制优化,sum%2==1,直接不能

判断dp[sum/2]==sum/2

ac:

#include<bits/stdc++.h>
#define inf 0x3f3f3f
#define MAXN 500005
using namespace std;
int a[MAXN],c[MAXN];
int dp[MAXN];

void onepack(int m,int v,int w)
{
    for(int i=m;i>=v;i--)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void compack(int m,int v,int w)
{
    for(int i=v;i<=m;i++)
        dp[i]=max(dp[i],dp[i-v]+w);
}

void multpack(int m,int v,int w,int num)
{
    if(v*num>=m)
    {
        compack(m,v,w);
        return ;
    }
    int k=1;
    for(k=1;k<=num;k<<=1)
    {
        onepack(m,k*v,k*w);
        num=num-k;
    }
    if(num)
        onepack(m,num*v,num*w);
}

int main()
{
    int cas=1;
    while(1)
    {
        int sum=0,flag=0;
        for(int i=1;i<=6;i++)
        {
            a[i]=i;
            scanf("%d",&c[i]);
            sum+=c[i]*a[i];
        }
        if(!sum)
            break;
        if(sum%2==0)
        {
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=6;i++)
                multpack(sum/2,a[i],a[i],c[i]);
            if(dp[sum/2]==sum/2)
                printf("Collection #%d:\nCan be divided.\n\n",cas);
            else
                printf("Collection #%d:\nCan't be divided.\n\n",cas);
        }
        else{
            printf("Collection #%d:\nCan't be divided.\n\n",cas);
        }
        cas++;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值