• codevs 1297 硬币 [dp]


    题目描述 Description

    我们知道即使是同一种面值的硬币,它们的重量也有可能不一样,因为它受到许多因素的影响,包括制造工艺和流程上的。但是任何一种面值的硬币的重量总是处于某个特定范围之内。现在已知所有面值的硬币的重量范围。给定一堆硬币的总重量,问这堆硬币的总价值有多少种不同的可能。举例:已知一角硬币的重量在19到21之间,五角硬币的重量在40到43之间。有一堆硬币的总重量为99。则它可以由4个重量为20,1个重量为19的一角硬币组成,其总价值为5角,也可以由1个重量为42的五角硬币和3个重量为19的一角硬币组成,其总价值为8角,再或者由2个重量为40的五角硬币和1个重量为19的一角硬币组成,其总价值为1块1角。因此这堆硬币的总价值共有3种不同的可能。

    输入描述 Input Description

    第一行是一个整数w(10<=w<=100)表示所有硬币的总重量。第二行是一个整数n(1&lt;=n<=7)表示不同面值的硬币总数。接下来n行每行3个整数,依次表示硬币的面值,最小可能重量和最大可能重量。硬币面值不超过50,最小重量不低于2,最大重量不高于100。最大重量和最小重量之间的差距不超过30。

    输出描述 Output Description

    仅包括一行表示这堆硬币的总价值有多少种不同的可能性。

    样例输入 Sample Input

    99

    2

    1 19 21

    5 40 43

    样例输出 Sample Output

    3



    d[i][j][k]表示前i种硬币,重量为j总价值为k的方案是否存在。用完全背包的思路将第一维去掉,保留d[j][k]。

    则d[j][k] = d[j-w[i]][k-v[i]],  w[i]表示第i种硬币的重量,v[i]表示价值。题目给的硬币重量是一个范围,那就在这个范围内枚举。

    即 d[j][k] = or { d[j-wt][k-v[i]]} , 其中 w[i].from <= wt <= w[i].to 

    加上一些剪枝就没问题了。

    总价值最大为2500。


    #include<cassert>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<set>
    #include<queue>
    #include<map>
    using namespace std;
    #define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
    #define dep(i,f,t) for(int i = (f), _end = (t); i >= _end; --i)
    #define clr(c,x) memset(c,x,sizeof(c));
    #define debug(x) cout<<"debug  "<<x<<endl;
    const int INF = 0x3f3f3f3f;
    typedef long long int64;
    
    inline int RD(){ int res; scanf("%d",&res); return res; }
    
    #define Rush for(int casn = RD(), cas = 1; cas <= casn; ++cas)
    
    //*******************************************************************************
    
    const int maxn = 10;
    int v[maxn];
    pair<int,int> w[maxn];
    bool d[110][2501];
    int main(){
        int W,n;
        scanf("%d%d",&W,&n);
        rep(i,1,n){
            scanf("%d%d%d",&v[i],&w[i].first,&w[i].second);
        }
        d[0][0] = 1;
        rep(i,1,n){
            rep(j,w[i].first, W){
                rep(k,v[i], 2500){
                    if(d[j][k])continue;
                    rep(wt,w[i].first,min(j,w[i].second)){
                        assert(j-wt>=0);
                        assert(k-v[i]>=0);
                        d[j][k] |= d[j-wt][k-v[i]];
                        if(d[j][k])break;
                    }
                }
            }
        }
        int ans = 0;
        rep(k,1,2500)if(d[W][k])++ans;
        cout<<ans;
        return 0;
    }
    


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    bzoj 2038 [2009国家集训队]小Z的袜子(hose)
    搭配飞行员
    codevs 1022 覆盖
    Tyvj-1338 QQ农场
    bzoj 3894 文理分科
    bzoj 1877 [SDOI2009]晨跑
    poj 3304 判断是否存在一条直线与所有线段相交
    poj 2318 向量的叉积二分查找
    poj 3608 凸包间的最小距离
    LA 4728 旋转卡壳算法求凸包的最大直径
  • 原文地址:https://www.cnblogs.com/DSChan/p/4861984.html
Copyright © 2020-2023  润新知