zoukankan      html  css  js  c++  java
  • hdu2069

    博客图片

    最少硬币组合问题

            给出(n)中硬币面值,不限定硬币的数量,计算某个金额所需的最下的硬币的数量.对应的递推方程如下:(Min(x) = min {Min(x),Min(x-v(i))+1}).Min(x)表示金额为x的硬币所需的最小的数量,v(i)表示第i中硬币的面值.

            这里面没有对硬币的数量进行限制,那如果对硬币的数量添加一些限制,有该怎么解决?再添加一些其他条件呢,比如某个两种硬币不能同时使用?用贪心能不能解决这类最小硬币组合问题?

    打印最小硬币组合的方案

            为了输出最小硬币组合的的方案,需要一个额外的数据记录最后一次选择的硬币的种类.假设Path[x]记录的是金额为(x)时需要的最后一枚硬币的种类,其值为v[i],那么可以根据Path[x-v[i]]找到倒数第二枚硬币的种类v[j],重复执行,直到x-v[i]的值为0.

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1000;
    const int M = 5;
    ll Min[N];
    ll Path[N];
    const int values[] = {1, 5, 10, 20, 50};
    
    void solve(){
        fill(Min, Min + N,N+1);
        memset(Path, 0, sizeof(Path));
        Min[0] = 0;
        for (int i = 0;i < N; ++i){
            for (int j = 0; j < M; ++j){
                if( i >= values[j]){
                    if( Min[i] > Min[i-values[j]]+1){
                        Min[i] = Min[i - values[j]] + 1;
                        Path[i] = values[j];
                    }
                }
            }
        }
    }
    
    

    打印所有的硬币组合方案

            给出集中硬币,计算某种金额可能的组合方案数目.

    硬币数量没有限制

    void solve(){
        dp[0] = 1;
        for (int i = 0; i < M; ++i){
            for (int j = values[i]; j < N; ++j){
                dp[j] += dp[j - values[i]];
            }
        }
    }
    

            先计算每种金额使用第一种硬币的数目,再将每种金额使用第二种的硬币的方法数加到前一种.注意这里面因为每种金额的数量是依赖于前面的的方法数dp[j] += dp[j-values[i]],dp[j]使用1种面额为values[i]的硬币,那么要将dp[j-values[i]]可能的方法数加入到dp[j]中,而dp[j-values[i]]也可能使用了values[j]这种硬币也可能没用,所以dp[j]的每一轮就散依赖于前一轮计算更新的结果,并且本轮更新的结果会影响下一轮,所以遍历所有金额的循环放在了内层,遍历金额数目的放在了外层,因为这个要找到所有解;而前面那个找最优解的遍历所有金额的放在外层,遍历金额的放在内层,也就是经过一轮内层循环一定可以找到该金额的最优解,并且该金额的最优解依赖于前面的最优解.尤其注意着两种循环结构的区别.一个是最优解,经过一轮内层循环就可以计算出来,一个是所有解,需要不断更新所有金额的解的数量.

    使用的硬币总数有限制

            这时要在原来的dp数组上多加一个数量限制,特别地,当i!=0时,dp[i][0]=1,从而可以处理由于硬币数量超限,额没法构成一种组合方案,对原来的方法稍加变换可以得到一个dp[i][j],使用j枚硬币,可以构成i金额的方法数,如果要求最多使用硬币数量,要对应的进行一个累加.

    void solve() {
        dp[0][0] = 1;
        for (int i = 0; i < M; ++i){
            for (int j = 1; j < nums; ++j){
                for (int k = values[i]; k < N; ++k){
                    dp[k][j] += dp[k - values[i]][j - 1];
                }
            }
        }
        for (int i = 0; i < N; ++i){
            for (int j= 0; j < nums; ++j){
                ans[i] += dp[i][j];
            }
        }
    }
    

    题目链接

    hdu2069

  • 相关阅读:
    HIVE 技巧积累之合并重叠日期
    记一次hive版本升级
    【转】elasticsearch中字段类型默认显示{ "foo": { "type": "text", "fields": { "keyword": {"type": "keyword", "ignore_above": 256} }
    【转】深入理解Linux修改hostname
    VMware中 CentOS7挂载windows共享文件夹
    Apache版hadoop编译
    No route info of this topic
    java遍历文件夹及所有子文件
    关闭spring整合kafka时,消费者一直打印kafka日志
    (转)详解shell中>/dev/null 2>&1到底是什么
  • 原文地址:https://www.cnblogs.com/2018slgys/p/13344436.html
Copyright © 2011-2022 走看看