换钱方法数(有限制条件和无限制条件)

1.  先说一下有限制的

/*
给定一套货币(面值不同的一组货币) vector<int> moeys,以及每种货币的数量vector<int> cnts,求出组合成目标tar的方法数

动态规划思想: dp[i][j]表示用货币moneys[0~i] 组合成 tar 的方法数
dp的规模是:dp[moneys.size()][tar+1]

<1> 初始化第一行,dp[0][j], 用moneys[0] 组成j的方法数, moneys[0]只能组成其整数倍的钱数
<2> 初始化第一列, dp[i][0], 用任何面值组成0的方法都是1,即都不用,所以第一列是全1
<3> 其他位置:dp[i][j]有以下几种可能
    <3.1> 不用moneys[i], 只用moneys[0~i-1]组成j,此时方法数是dp[i-1][j]
    <3.2> 用一张moneys[i], 且用moneys[0~i-1]组成j-1*moneys[i],此时方法数是dp[i-1][j-1*moneys[i]]
    <3.3> 用两张moneys[i], 且用moneys[0~i-1]组成j-2*moneys[i],此时方法数是dp[i-1][j-2*moneys[i]]
    <3.4> 用三张moneys[i], 且用moneys[0~i-1]组成j-3*moneys[i],此时方法数是dp[i-1][j-3*moneys[i]]
    .
    .
    .
    直到 当前货币张数用完,或者j-k*moneys[i]<0 则停止
    那么dp[i][j] 就是上面所有可能的对应的方法数的和。  dp[i][j] = sum{dp[i-1][j-k*moneys[i]], 其中k=0,1,2,3...cnts[i] ,且j-k*moneys[i]}
*/

#include <bits/stdc++.h>
using namespace std;

int getChangeWays(vector<int> &moneys, vector<int> &cnts, int tar)
{
    int len1=moneys.size(), len2=cnts.size();
    int dp[len1][tar+1];
    // 初始化第一列
    for (int i=0; i<len1; i++) dp[i][0] = 1;
    /*
    初始化第一行,注意里面的细节:
    <1> 对于小于moneys[0]的j,其值是0,(如:5元纸币是无法组成1~4元的)
    <2> 只有moneys[0]的整数倍,且不成超过张数限制的位置, dp[0][j] 才是1.(如:假如有4张5元纸币,那么能组成的面值
    有5 10 15 20, 但是 25 30 .. 是5的整数倍但是由于张数不够,所以无法组成)
    */
    for (int j=1; j<=tar; j++)
    {
        if (j>=moneys[0] && j%moneys[0]==0 && (j/moneys[0])<=cnts[0]) dp[0][j] = 1;
        else dp[0][j] = 0;
    }

    // 其他位置dp[i][j]
    for (int i=1; i<len1; i++)
    {
        for (int j=1; j<=tar; j++)
        {
            int ways = 0;
            /*
            用k张当前货币,所对应的方法数是dp[i-1][j-k*moneys[i]].
            这里要保证0<=k<=cnts[i], 且 j-k*moneys[i]>=0
            */
            for (int k=0; k<=cnts[i] && (j-k*moneys[i])>=0; k++)
            {
                ways += dp[i-1][j-k*moneys[i]];
            }
            dp[i][j] = ways;
        }
    }
    return dp[len1-1][tar];
}

int main()
{
    int tar;
    int arr[] = {1,5,10,20,50,100}; // 给出货币面值
    vector<int> moneys(arr,arr+6);
    cin>>tar;
    vector<int> cnts(6,0);     // 每种货币的数量
    for (int i=0; i<6; i++)
    {
        cin>>cnts[i];
    }
    cout<<getChangeWays(moneys, cnts, tar)<<endl;
    return 0;
}

2.  如果上面的,理解了的话,就进行无限制的情况

无限制和有限制的区别,主要体现在两处:

<2.1> 初始化第一列的时候, 没有了数量上的限制

<2.2> 求其他位置dp[i][j] 的时候,约束条件少了一条,并且可以减少一部分运算

/*
状态转化方程是:dp[i][j] = sum{dp[i-1][j-k*moneys[i]], 其中k=0,1,2,3... 且j-k*moneys[i]>=0}
换个形式
dp[i][j] = dp[i-1][j] + sum{dp[i-1][j-k*moneys[i]], 其中k=1,2,3... 且j-k*moneys[i]>=0}                        // 把第一项单独拿出来
         = dp[i-1][j] + sum{dp[i-1][j-moneys[i]-k*moneys[i]], 其中k=0,1,2,3... 且j-moneys[i]-k*moneys[i]>=0}
	 = dp[i-1][j] + dp[i][j-moneys[i]]
*/  

这时候的函数是下面的这个

int getChangeWays2(vector<int> &moneys, int tar)
{
    int len1=moneys.size(), len2=cnts.size();
    int dp[len1][tar+1];
    // 初始化第一列和第一列
	for (int i=0; i<len1; i++) dp[i][0] = 1;
	for (int j=1; j<=tar; j++)
    {
        if (j>=moneys[0] && j%moneys[0]==0) dp[0][j] = 1;
        else dp[0][j] = 0;
    }

	// 其他位置dp[i][j]
    for (int i=1; i<len1; i++)
    {
        for (int j=1; j<=tar; j++)
        {
            dp[i][j] = dp[i-1][j];
			if (j-moneys[i]>=0) dp[i][j] += dp[i][j-moneys[i]];
        }
    }
    return dp[len1-1][tar];
}  

如果有写错的地方,还请各位大神指出!!!

参考:

左程云 《程序员代码面试指南》

http://blog.csdn.net/qq_22222499/article/details/71249354

时间: 2024-11-01 12:25:52

换钱方法数(有限制条件和无限制条件)的相关文章

解决方法数超65535问题

构建工具: ANT: 在project.properties文件中添加dex.force.jumbo=true 1.生成一个超大的dex             2.优化方法数降至满足条件即可(和混淆包的优化方法数有所区别)             3.如果方法数超过很多也不能运行             4.该属性没经过大量测试验证所以打包发布切记不要加这个属性 Gradle:multiDexEnabled true

android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题!

ndroid-Easy-MultiDex 项目地址:TangXiaoLv/Android-Easy-MultiDex 简介:Android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题! 注 1:不想看前半部分的话可以直接跳过到最下面配置部分.注 2:本插件是基于DexKnifePlugin 1.5.6优化改造而来,感谢 ceabie 的无私奉献. 填坑之路 坑 1:65536 ,So easy! 原因:Dalvik 的 invoke-kind 指令集中,method refere

彻底解决Android 应用方法数不能超过65K的问题

尊重原创 :http://blog.csdn.net/yuanzeyao/article/details/41809423 作为一名Android开发者,相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik format failed:Unable toexecute dex: method ID not in [0, 0xffff]: 65536 可能有些同学会说,解决这个问题很简单,我们

HDU 2157 How many ways??:矩阵快速幂【i到j共经过k个节点的方法数】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2157 题解: 给你一个有向图,n个节点m条边,问你从i到j共经过k个节点的方法数(不算i点). 题解: 先用邻接矩阵存图. 假设k = 2,那么从i到j的方法数 = ∑ way[i][x] * way[x][j] (0<=x<n && x!=i && x!=j) 诶?快看,那是矩阵乘法! 设邻接矩阵为A,若i到j有边则val[i][j] = 1. k = 2时答案矩

Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚

如有转载,请声明出处: 时之沙: http://blog.csdn.net/t12x3456    (来自时之沙的csdn博客) 随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 6553

安卓应用方法数超过64k解决办法:分割Dex

你的安卓项目功能很强大,对接了好多第三方开源库,项目越做越完善,代码越敲越爽.可是突然有一天报异常了. 错误:The number of method references in a .dex file cannot exceed 64K. 编译器提醒你,你的项目方法数超过64k了. AndroidStudio会提醒你: Learn how to resolve this issue at https://developer.android.com/tools/building/multidex

使用android-support-multidex解决Android方法数超过65535的问题

随着应用不断更新,业务的不断增加, 应运而生的应用可能需要集成了各种第三方library,相信很多人都遇到过如下类似的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501) at com.android.

Android应用打破65K方法数限制

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: <span style="color:#ff0000;">UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge

Android 使用android-support-multidex解决Dex超出方法数的限制问题

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java: