zoukankan      html  css  js  c++  java
  • Coins

    Coins

    有n个硬币,第i个硬币的价值(a_i),数量(c_i),现在求这些硬币组成的1~m以内的钱的个数,(1<=n<=100,m<=100000,c_ileq 1000)

    法一:二进制拆分优化01

    注意到这类似多重背包,多个选择,关键在于数据范围过大,于是可以采取二进制拆分优化。

    参考代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define il inline
    #define ri register
    using namespace std;
    bool dp[100001];
    int a[101],c[101],w[1001],wt;
    il void read(int&);
    int main(){
        int n,m,i,j,k,ans;
        while(read(n),read(m),n&&m){
            memset(dp,0,sizeof(dp)),wt&=0;
            for(i=1;i<=n;++i)read(a[i]);
            for(i=1;i<=n;++i)read(c[i]);
            for(i=1;i<=n;++i){
                j=1;
                while(c[i]-j>=0){
                    w[++wt]=a[i]*j;
                    c[i]-=j,j<<=1;
                }w[++wt]=a[i]*c[i];
            }dp[0]|=true,ans&=0;
            for(i=1;i<=wt;++i)
                for(j=m;j>=w[i];--j)
                    dp[j]|=dp[j-w[i]];
            for(i=1;i<=m;++i)ans+=dp[i];
            printf("%d
    ",ans);
        }
        return 0;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    

    法二:阶段内转移优化

    此题关注的是可行性,而多次选择一个硬币类似完全背包,考虑阶段内转移优化,而设(dp[j])为前i种硬币,是否组成钱为j,而(u[j])表示组成钱j的最少需要钱i的个数。

    于是当这个钱已经能组成,当然无需再组成,当这里没有组成,前面已经有组成的方案,比较前面的使用的该种硬币的个数,是否满足题意,即是否超越已用硬币数,之所以可行,是因为传统多重背包要求了权值最大,而使用的物品最少并不能保证权值最大,本题要求可行性,于是我们只要硬币数用的足够少,来保证组成尽可能多的硬币,于是仿照完全背包,顺序枚举

    [dp[j]|=true(!dp[j]&&dp[j-a_i]&&u[j-a_i]<c_i) ]

    边界:(dp[0]=1)

    答案:枚举累加有1的数即可

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define il inline
    #define ri register
    using namespace std;
    bool dp[100001];
    int used[100001],a[101],c[101];
    il void read(int&);
    int main(){
        int n,m;while(read(n),read(m),n&&m){
            for(ri int i(1);i<=n;++i)read(a[i]);
            for(ri int i(1);i<=n;++i)read(c[i]);
            memset(dp,0,sizeof(dp)),dp[0]|=true;
            for(ri int i(1),j;i<=n;++i){
                memset(used,0,sizeof(used));
                for(j=a[i];j<=m;++j)
                    if(used[j-a[i]]<c[i]&&dp[j-a[i]]&&!dp[j])
                        dp[j]|=true,used[j]=used[j-a[i]]+1;
            }int ans(0);
            for(ri int i(1);i<=m;++i)ans+=dp[i];
            printf("%d
    ",ans);
        }
        return 0;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    Servlet的生命周期
    HTTP协议简单记录
    Tomcat和JavaWeb目录和流程
    02 html 表格表单
    01 初识HTML
    Python 利用pywin32批量将doc转换成docx再读取成一行存入excel
    power bi 数据红绿灯详细用法
    Linux和Windows启动后台程序
    MySQL导出数据字典
    适用于渗透测试不同阶段的工具收集整理
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10917593.html
Copyright © 2011-2022 走看看