HDU 1085 Holding Bin-Laden Captive!【母函数||多重背包】

题意:给你cnt[0]个一元硬币,cnt[1]个两元硬币,cnt[2]个五元硬币,问不能凑出来的第一个面额是多少。

分析:不得不说遇到这个题的第一反应是多重背包265ms。一直跑到面额最大的数字,显然肯定能解决。另一种则是抽象成生成函数(母函数)加以解决64ms。

母函数模拟方式:
(1+x+x2+x3+.........xcnt1)(1+x2+x4+x6+.........xcnt2)(1+x5+x10+x15+............xcnt5)

母函数:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
#define ll long long int
const int maxn = 1e4 + 10;
int val[3] = { 1,2,5 }, cnt[3];
int c1[maxn], c2[maxn], mmax;
int main()
{
    while (~scanf("%d%d%d", &cnt[0], &cnt[1], &cnt[2]) && (cnt[0] || cnt[1] || cnt[2]))
    {
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        mmax = 0;
        for (int i = 0; i < 3; i++)  mmax += cnt[i] * val[i];
        for (int i = 0; i <= cnt[0]; i++) c1[i] = 1;
        for (int i = 1; i < 3; i++) {
            for (int j = 0; j <= mmax; j++) {
                if (c1[j]) {
                    for (int k = 0; k <= val[i] * cnt[i]; k += val[i]) {
                        if (j + k <= mmax) {
                            c2[j + k] += c1[j];
                        }
                    }
                }
            }
            memcpy(c1, c2, sizeof(c1));
            memset(c2, 0, sizeof(c2));
        }
        int i;
        for (i = 0; i <= mmax; i++) { 
            if (c1[i] == 0) 
                break; 
        }
        printf("%d\n", i);
    }
    return 0;
}

多重背包:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
#define ll long long int
const int maxn = 1e4 + 10;
//f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]} 多重背包
int val[3] = { 1,2,5 };
int cnt[3]; int mmax;
int dp[maxn];
int main()
{
    while (~scanf("%d %d %d", &cnt[0], &cnt[1], &cnt[2]) && (cnt[0] || cnt[1] || cnt[2]))
    {
        memset(dp, 0, sizeof(dp));
        mmax = 0;
        for (int i = 0; i < 3; i++)
        {
            mmax += cnt[i] * val[i];
        }
        dp[0] = 1;
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < cnt[i]; j++)
            {
                for (int k = mmax; k >= val[i]; k--)
                {
                    dp[k] = (dp[k]+dp[k - val[i]]);
                }
            }
        }
        int i;
        for (i = 1; i <= mmax; i++)
        {
            if (dp[i] == 0)
                break;
        }
        printf("%d\n", i);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值