• I


    http://acm.hdu.edu.cn/showproblem.php?pid=2844

     

    这个题目是一个多重背包转化成01背包

    题意: Whuacmers拥有bi个面值为ai的硬币,现在他要用这些硬币买价格不超过m的一个物品,问你最多能刚好能用硬币付钱的物品价格有几个(即该价格能用这些硬币凑出来)。

    思路: 看到多重背包问题,第一时间想到的是转化为01背包来做,即我们把这个物品能选取多次当成有多个相同的物品给我们选取,复杂度是o(m*(bi的和)),根据题目给出的数据范围,这个方法的复杂度是妥妥的TLE的,我们需要对这个方法进行优化,我们可以用二进制的思想来考虑.

    将第i种物品分成若干件01背包中的物品,其中每件物品有一个系数。这件物品的费用和价值均是原来的费用和价值乘以这个系数。令这些系数 分别为1,2,22…2k−1,bi−2k+1,且k是满足bi−2k+1 > 0的最大整数。例 如,如果bi为13,则相应的k = 3,这种最多取13件的物品应被分成系数分别 为1,2,4,6的四件物品。 分成的这几件物品的系数和为bi,表明不可能取多于bi件的第i种物品。另 外这种方法也能保证对于0…bi间的每一个整数,均可以用若干个系数的和表示。

    下面是一个模板,我觉得写的特别好

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e6 + 10;
    int num[maxn], dp[maxn], val[maxn];
    int N,V;
    
    void zero(int weight,int value)
    {
        for(int i=V;i>=weight;i--)
        {
            dp[i] = max(dp[i], dp[i - weight] + value);
        }
    }
    
    void all(int weight,int value)
    {
        for(int i=weight;i<=V;i++)
        {
            dp[i] = max(dp[i], dp[i - weight] + value);
        }
    }
    
    void solve()
    {
        int t = 1;
        int ncount = 0;
        for(int i=1;i<=N;i++)
        {
            if (num[i] * val[i] >= V) all(val[i], val[i]);
            else
            {
                t = 1;
                ncount = num[i];
                while(t<=ncount)
                {
                    zero(t*val[i], t*val[i]);
                    ncount -= t;
                    t *= 2;
                }
                zero(ncount*val[i], ncount*val[i]);
            }
        }
    }
    
    int main()
    {
        while(cin>>N>>V&&N!=0&&V!=0)
        {
            for (int i = 1; i <= N; i++) scanf("%d", &val[i]);
            for (int i = 1; i <= N; i++) scanf("%d", &num[i]);
            memset(dp, -inf, sizeof(dp));
            dp[0] = 0;
            solve();
            int ans = 0;
            for(int i=1;i<=V;i++)
            {
                if (dp[i] > 0) ans++;
                //printf("dp[%d]=%d
    ",i, dp[i]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    文档重复检测软件 DuplicateDetector
    Afinal 0.2.1 发布 Android的快速开发框架
    CshBBrain 4.0 发布,高性能WebSocket服务器
    英特尔的 C++ 编译器发布 13.0 版本
    Perl 5.16.2 发布
    OpenBSD 5.2 发布
    Webconverger 15.1 发布,适合网吧的 Linux
    Spring Framework 3.2 RC1 发布
    Postgres 9.2 新特性之:范围类型 (Range Types)
    Expression Blend实例中文教程系列文章汇总
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/10914757.html
Copyright © 2020-2023  润新知