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();
    }
    
    
  • 相关阅读:
    (转)一个JavaWeb项目开发总结
    (转)JAVA之桥接模式
    (转)Singleton 单例模式(懒汉方式和饿汉方式)
    (备忘)android模拟器摄像头模拟
    (原创)android中使用相机的两种方式
    (转)android中颜色矩阵colormatrix
    android中paint的setXfermode属性
    【贾志豪NOIP模拟题】慰问员工 cheer 【最小生成树】【对边权值的一些处理】
    【洛谷1340】兽径管理(最小生成树 Kruskal)(sort的一些技巧)【2012福建省信息学奥林匹克CCF NOIP夏令营第05天训练】
    【CSP2019】【洛谷5657】格雷码
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10917593.html
Copyright © 2011-2022 走看看