zoukankan      html  css  js  c++  java
  • 背包方案数问题(礼物)

    给个题面——hdu2126

    数字组合-背包方案数问题

    简述:给你n块钱,有m种钱币,每种钱币只能用一次,问组成n块钱有多少种方法。

    给个数据(结果对1e7+7取模):

    Input

    6 25

    8 9 8 7 16 5

    Output

    15

    Input

    30 250

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

    output

    6509431

    Analysis

    这是一道想法很清奇的dp题。思维难度和代码难度都较大。

    既然你要考虑用dp做,那你肯定会毫无疑问地去选择前(i)个物品,选(j)个和钱数(k)作为状态,用背包来计算方案数。

    也就是

    [dp[i][j][k] += dp[i-1][j][k] ]

    [if(k >= v[i]) dp[i][j][k] += dp[i-1][j-1][k-v[i]] ]

    事实上这样会超时。

    所以要怎么做?

    有大佬用更好的方法,思路诡异。

    先将物品排升序,枚举状态(i),表示第(i)个物品是未被选的物品中价值最小的一个物品。

    那么价值比它小的物品,都在它左面,而且都会被选,把他们用前缀和维护起来。

    现在你剩余一些钱(j),从后面选取一些物品使价值最大但不超过(j),这就是背包。

    所以一共二维,时间复杂度空间复杂度皆降低,完美。

    咳咳,这是人能想出来的吗……

    Code

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    const int MAXN=1010;
    const int mod=1000000007;
    using namespace std;
    ll dp[MAXN][MAXN],n,m,minn,w[MAXN];
    ll sum[MAXN];
    int cmp(int a,int b){ return a>b; }
    
    int main(){
        scanf("%lld%lld",&n,&m);
        for ( int i=1;i<=n;++i) scanf("%lld",&w[i]); dp[0][0]=1;
      sort(w+1,w+n+1,cmp);
        for (int i=n;i;--i) sum[i]=sum[i+1]+w[i];
        ll ans=0;
        for(int i=1;i<=n;i++){
            for(int j=m-sum[i+1];j>=0&&j>m-sum[i+1]-w[i];j--)
                ans+=dp[i-1][j],ans%=mod;
            for(int j=m;j>=0;j--){
                dp[i][j]=dp[i-1][j];
                if(j-w[i]>=0) dp[i][j]+=dp[i-1][j-w[i]],dp[i][j]%=mod;
            }
        }
        if(sum[1]<=m) ans++,ans%=mod;
        printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    python!让人惊讶的python
    由测试中的版本同步联想到敏捷开发中的两个实践
    python中比较两个文件是否相同
    python中根据类名生成类的实例
    使用sqlServer开发应用程序时要注意的10件事
    python版的Hello World
    其他语言的.net实现列表
    Bug管理的流程和几个重点
    IL Reference
    Delphi CreateProcess函数调用示例
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/9607682.html
Copyright © 2011-2022 走看看