【牛客--0002】-钱币拼凑

题目:给你六种面额 1、5、10、20、50、100 元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0~10000的非负整数)的不同组合的个数。 

时间空间限制

    时间限制:1秒

    空间限制:32768K

输入描述

     输入包括一个整数n(1 ≤ n ≤ 10000)

输出描述

     输出一个整数,表示不同的组合方案数

输入例子1
   1

输出例子1

    1

解题思路

      这道题是一道经典的动态规划题目。题目意思是给定一个输入N,假设我们有m中不同面值的钱币v1,v2,v3...,Vm,则用这m中不同的钱币组合成N,即N=t1*v1+t2*v2+t3*v3+...+tm*Vm    (t1...tm表示所需不同面值钱币对应的次数),求t1,t2...tm的组合数。

即求有多少种t1,t2...tm满足N=t1*v1+t2*v2+t3*v3+...+tm*Vm

动态规划思想:

   定义dp[i][total] 表示前i种钱币组合成total的组合次数。假设我们前面所有钱币已经组合成功,则最后一种钱币的所有可能取法为tm=0,1,2...k,其中k=total/Vm;

当tm=0, dp[i][total]=dp[i-1][total]

当tm=1,dp[i][total]=dp[i-1][total-1*Vm]

....

当tm=k,dp[i][total]=dp[i-1][total-k*Vm]

所有组合数就是dp[i][total]=dp[i-1][total]+dp[i-1][total-1*Vm]+....+dp[i-1][total-k*Vm]

初始化用一个二维数组dp[i][total]来表示前i中钱币拼凑成total的组合数。开始初始化数组dp[i][total]全部为0;

然后初始化total=0的时候,dp[i][0]=1,表示总的钱币为0的时候,组合情况只有一种即取钱币0。

由于最后一种钱币的取法依赖于前一种钱币的取法,所以先求出前i-1中的钱币组合,再求最后一种。以此类推,从头依次向后遍历即可,最后dp[i][total] 为题目所求。

代码如下

import java.util.Scanner;

public class CoinFen {
	
	public static void main(String[] args) {
		    int [] coins= {1,5,10,20,50,100};  //所有钱币的种类
		    Scanner in=new Scanner(System.in);
		    int n=in.nextInt();      //待拼凑钱币总数
		    System.out.println(getCombinetimes(n,coins));
	}
	//求解所有组合数,由于组合数超过Integer.MAXVALUE故使用long类型
	public static long getCombinetimes(int N,int[]coins) {
		int coinsVariety=coins.length;   //钱币的种类数
		long [][] dp=new long[coinsVariety+1][N+1];
		//初始化
		for(int i=0;i<=coinsVariety;i++) {
			for(int j=0;j<=N;j++) {
				dp[i][j]=0;   //初始化
			}
		}
		//N=0的时候
		for(int i=0;i<=coinsVariety;i++) {  //拼凑的钱币为0的时候只有一种组合数即选0个钱币这一种可能。
			dp[i][0]=1;
		}
		
		for(int i=1;i<=coinsVariety;i++) {  //遍历钱币所有种类
			for(int j=1;j<=N;j++) {        //拼凑钱币数
				dp[i][j]=0;
				for(int k=0;k<=j/coins[i-1];k++) {   //对于每一中钱币,相对于平凑钱币数j所有可能取法
				  dp[i][j]+=dp[i-1][j-k*coins[i-1]];
				}
			}
		}
		return dp[coinsVariety][N];
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_42289193/article/details/81561894