多重背包 -> hdu 2844 Coins 多重部分和问题 && hdu 1059

PS:真心后悔没有把大白带回家

数组可以重复利用,i是没必要的,否则会MLE

hdu 2844 Coins

题意:和大白上差不多,a是数值,c是数的个数,问从这些数中选出一些数,能形成多少个m以内(包括m)的结果

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[110],c[110];
int dp[100010];                        //dp[i][j]为钱为j时剩下的第i种硬币的数量
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF&&n&&m)
    {
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;++i)
            scanf("%d",&c[i]);
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<=n;++i)
            for(int j=0;j<=m;++j)
            {
                if(dp[j]>=0)                   // !-1说明前i-1种硬币加和能得到j,因此第i种硬币不需要消耗
                    dp[j]=c[i];
                else if(j<a[i]||dp[j-a[i]]<=0)   //第i种硬币面值太大,或者太小(前i种硬币无法凑到j-a[i]或者是硬笔数用完了,自然就不可能凑到j)
                    dp[j]=-1;
                else
                    dp[j]=dp[j-a[i]]-1;
            }
        int ans=0;
        for(int j=1;j<=m;++j)
            for(int i=1;i<=n;++i)
            {
                if(dp[j]>=0)
                {
                    ++ans;
                    break;
                }

            }
        printf("%d\n",ans);


    }
}

我们学校已经毕业的巨巨的题解,感觉这个更好,果断放弃自己的!

#include <cstdio>
#include <cstring>
int const MAXM = 1e5 + 5;
int const MAXN = 1e2 + 5;
bool dp[MAXM];
int cnt[MAXM];
int a[MAXN], c[MAXN];
 
int  main()
{
    int n, m;
    while(scanf("%d %d", &n, &m) != EOF && (n + m))
    {
        memset(dp, false, sizeof(dp));
        for(int i = 1; i <= n; i ++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &c[i]);
        dp[0] = true;
        int ans = 0;
        for(int i = 1; i <= n; i ++)
        {
            memset(cnt, 0, sizeof(cnt));
            for(int s = a[i]; s <= m; s ++)
            {
                if(!dp[s] && dp[s - a[i]] && cnt[s - a[i]] < c[i])
                {
                    dp[s] = true;
                    ans ++;
                    cnt[s] = cnt[s - a[i]] + 1;
                }
            }
        }
        printf("%d\n", ans);
    }
}

hdu 1059 dividing

题意:总共有六种收藏品,给出每种的个数,问是否能把它们分成价值相等的两份

思路:转化成是否能凑出价值和的一半

120000*20000*6 普通的多重背包做会T   于是就和上面一样啦

坑点:样例之间要空一行!!!!!怪我没有认真审题!

还因为忘了用continue,以及数组开小了,wawawa

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
//6*20000
const int maxv=120010;
//int dp[maxv];
bool dp[maxv];
int v[10],c[10];
int cnt[maxv];                                                              //cnt一开始开成6 开小了!
int main()
{
    int kase=0;
    while(scanf("%d%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&c[5],&c[6])!=EOF)
    {
        if(!c[1]&&!c[2]&&!c[3]&&!c[4]&&!c[5]&&!c[6])
            break;
        int sum=0;
        for(int i=1;i<=6;++i)
        {
             v[i]=i;
             sum+=v[i]*c[i];
        }
        if(sum%2)
        {
             printf("Collection #%d:\n",++kase);
             printf("Can't be divided.\n\n");
             continue;                                      //忘记continue wa 了一发
        }
        memset(dp,false,sizeof(dp));
        dp[0]=true;
        int ans=0;
        for(int i=1;i<=6;++i)
        {
            memset(cnt,0,sizeof(cnt));
            for(int j=v[i];j<=sum/2;++j)
            {
                if(!dp[j]&&dp[j-v[i]]&&cnt[j-v[i]]<c[i])
                {
                    dp[j]=true;
                    cnt[j]=cnt[j-v[i]]+1;
                    ans=max(ans,j);
                }
            }
        }
         printf("Collection #%d:\n",++kase);
        if(ans==sum/2)
            printf("Can be divided.\n\n");
        else
            printf("Can't be divided.\n\n");
     }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值