• dp复习 背包[礼物]


    【问题描述】
    人生赢家老王在网上认识了一个妹纸,然后妹纸的生日到了,为了表示自己的心
    意,他决定送她礼物。可是她喜爱的东西特别多,然而他的钱数有限,因此他想
    知道当他花一定钱数后剩余钱数无法再购买任何一件剩余物品(每种物品他最多
    买一个)时有多少种方案,两种方案不同,当且仅当两种方案中至少有一件品不
    同,可是由于他忙着准备泡下一个妹纸(chi),因此麻烦聪明的你帮帮忙。
    【输入格式】
    输入第一行 n 和 m, n 表示妹纸喜欢的礼物数目, m 表示现有的钱数,第二行 n
    个数,表示 n 个物品的价格。
    【输出格式】
    输出一行一个数表示方案数目,答案对 1000000007 取模。
    【 样例输入 1】
    gift.in
    6 25
    8 9 8 7 16 5
    【样例输出 1】
    gift.out
    15
    【数据范围】
    30%的数据: 0<=n<=100 0<=m<=500
    100%的数据:0<=n<=1000 0<=m<=1000
    注意:所有物品价格均小于 m

    题解:(wfj提供的思路)

    我们想如果我们设dp[i][j]表示前i个物品容量为j的方案数是多少,这个很好转,做背包就可以了,但怎么统计答案呢,我们可以先把物品从大到小排序,然后每次强制让第i个物品做我们没选的最小的数,那么后面比他小的就都要选上,前面就做一个背包就可以了,然后限制j自己推一下就看以了,最有不要忘记,如果可以全部选上也是一种方案。

    代码:

    #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);
    }
  • 相关阅读:
    Unity WebGL MoonSharp崩溃问题
    UISprite(NGUI)扩展 图片镂空
    自动化交易机器人Beta猪
    如何成为一个真正在路上的Linuxer
    课堂里学不到的C与C++那些事(一)
    Android ART运行时与Dalvik虚拟机
    用Dockerfile构建docker image
    论docker中 CMD 与 ENTRYPOINT 的区别
    sshfs远程文件系统挂载
    docker镜像与容器存储结构分析
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7296257.html
Copyright © 2020-2023  润新知