zoukankan      html  css  js  c++  java
  • hdu2844 & poj1742 Coin ---多重背包--两种方法

    意甲冠军:你有N种硬币,每个价格值A[i],每个号码C[i],要求。

    在不超过M如果是,我们用这些硬币,有多少种付款的情况下,。那是,:1,2,3,4,5,....,M这么多的情况下,,你可以用你的硬币不找零,种情况。

    比如:

    你有一种硬币,价值2。个数2,那么 你是不能付款 3元的。。你仅仅能付款2,或者4元。。

    OK,题意差点儿相同就是这样啦。

    那么这里有两种方式!

    分析:

    那么这里我们能够用多重背包来解决,我们把价值和重量看成一样的w[i] = A[i];用M作为背包。

    那么dp 过后。我们就能够知道 dp[i] 表示的含义为,不超过i元钱的情况下,用拥有的硬币能构成的最大钱数。那么非常明显,假设dp[i] = i,意思就是 用拥有的钱,能够刚好构成 i 元钱,上马:

    //281MS 648K
    #include <stdio.h>
    #include <string.h>
    
    #define MAX 102
    
    int ans;//最后答案
    int n,m;
    int A[MAX],C[MAX];
    int dp[100005];
    
    void ZeroOne(int V,int W)
    {
        for(int i = m; i >= V; i--)
            //dp[i] = dp[i]>dp[i-V]+W ?

    dp[i]:dp[i-V]+W; if(dp[i]<dp[i-V]+W) { dp[i] = dp[i-V]+W;//这里需改动如此统计 if(dp[i] == i) ans ++;//在dp过程中,会有出现dp[j]更新为j的时候 且仅仅有一次,也要放在dp[i]=dp[i-V]+W;此语句后 } } int main() { while(scanf("%d%d",&n,&m),n+m) { ans = 0; memset(dp,0,sizeof(dp)); for(int i = 1; i <= n; i ++) scanf("%d",&A[i]); for(int i = 1; i <= n; i ++) scanf("%d",&C[i]); for(int i = 1; i <= n; i ++) { if(A[i]*C[i] >= m) { for(int j = A[i]; j <= m; j ++) //dp[j] = dp[j]>dp[j-A[i]]+A[i] ? dp[j]:dp[j-A[i]]+A[i]; //将价值和重量看做同样 if(dp[j]<dp[j-A[i]]+A[i]) //这里需改动如此统计ans { dp[j] = dp[j-A[i]]+A[i]; if(dp[j] == j) ans ++; //在dp过程中,会有出现dp[j]更新为j的时候 且仅仅有一次,也要放在dp[i]=dp[i-V]+W;此语句后 } } else { int k = 1; while(k <= C[i]) { ZeroOne(A[i]*k,A[i]*k); C[i] -= k; k *= 2; } ZeroOne(C[i]*A[i],C[i]*A[i]); } } //for(int i = 1; i <= m; i ++) if(dp[i]==i)ans++;//这里用以用在hdu,可是poj须要用上面的方式统计ans,不然会超时,过了也过得非常险 2654ms........汗。。

    。。

    printf("%d ",ans); } return 0; }

    那么这里另一种方式

    用flag[i]表示能不能构成 钱为 i 的情况

    time[j] 表示,构成 j 元钱的时候,用第 i 种硬币的个数

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    #define MAX 100005
    
    int N,M;
    int A[MAX],C[MAX];
    bool flag[MAX];
    int time[MAX];
    
    int main()
    {
        while(cin >> N >> M)
        {
            if(!N && !M)break;
            for(int i = 0; i < N; i ++) cin >> A[i];
            for(int i = 0; i < N; i ++) cin >> C[i];
    
            int ans = 0;
            memset(flag,false,sizeof(flag));
            flag[0] = true;
            for(int i = 0; i < N; i ++){
                memset(time,0,sizeof(time));
                for(int j = A[i]; j <= M; j ++){//这里解释为。仅仅有当前j这样的情况没有构成,而且j-A[i]的情况存在--(这里也就是相似全然背包,这次状态应该依赖前面存在情况),同一时候到j为止。用第i种硬币的数量不超过C[i]的情况下才满足条件
                    if(!flag[j] && flag[j-A[i]] && time[j-A[i]]+1 <= C[i]){
                        flag[j] = true;
                        time[j] = time[j-A[i]]+1;
                        ans ++;
                    }
                }
            }
            cout << ans <<endl;
        }
        return 0;
    }
    
    个人愚昧观点,欢迎指正与讨论


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    C#代码
    属性面板:tabcontroller
    窗体效果
    c#窗体开发
    帝国cms学习
    在树莓派上运行 .net core 2.1 程序 并实现开机启动
    C# 高性能的数组 高性能数组队列实战 HslCommunication的SharpList类详解
    C# 序列化详解,xml序列化,json序列化对比
    C# 读写redis C#读写实时数据库
    python 读写三菱PLC数据,使用以太网读写Q系列,L系列,Fx系列的PLC数据
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4803581.html
Copyright © 2011-2022 走看看