Live2d Test Env

dp1:分钱的问题

问题:
有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱(n <= 100000),有多少中组合可以组成n分钱?

网址:https://www.nowcoder.com/question/next?pid=18874168&qid=587672&tid=29129649

  从题目来看是与华为的一道面试题相似,归属于简单的dp问题,首先定义dp[n],存放从0-n所需要的最小硬币数,v[i]存放硬币的面值,初始化dp[0] = 0,得出状态转移方程dp[i]=min{dp[i-1]+1,dp[i-v[j]] +1 };

 对于状态方程可以这样来理解:给定了n分钱,设i为使用的币种数目,最后一个币种的面值为k,假设全使用k币,则k的数目为n/k,那么就有式子:

      dp[i][n]=dp[i-1][n-0*k]+dp[i-1][n-1*k]+dp[i-1][n-2*k]+.......+dp[i-1][n-n/k*k];即所有情况包含:不使用k币,使用1张k币,使用2张k币.......全用k币,可以得到二位数组形式的状态转移方程;

  简化为一维dp方程为:dp[i]=dp[i]+dp[i-v[j]];

代码:

import java.util.Scanner;

public class Main {
    public static void main(String args[]) {
    Scanner input=new Scanner(System.in);
    int n=input.nextInt();
    int coins[]= {1,2,5,10};
    int [] dp=new int[100001];
    dp[0]=1;
    for(int i=0;i<4;i++) {
        for(int j=coins[i];j<=n;j++) {
            dp[j]=(dp[j]+dp[j-coins[i]])%1000000007;
        }
    }
    System.out.println(dp[n]);
    
    }
}

 

可以这样理解:对于每一个能够构成的总钱数,都可以像先前最开始二维数组推导的一样,使用1币1张,1币2张,2张1币,3张3币.......以此类推不停的迭代,钱j一直在增加,减去的币数也在不停的增加,下方的式子即为不停的迭代,减去

第1币,减去2币...后得到的方法数不停的迭代,即可得到所求的结果。

     代码的时间复杂度仅为O(n),远小于暴力求解法;

dp[j]=(dp[j]+dp[j-coins[i]])%1000000007;


 

 

posted @ 2019-11-05 22:39  lszz  阅读(216)  评论(0)    收藏  举报