这里讨论的是有几种方式可以得到这个数值,先上代码和运行结果
import java.util.Scanner;
public class A034_用硬币表示某个给定数值 {
public static void main(String[] args) {
int[] book = new int[] { 1, 5, 10, 25 };
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] a = new int[book.length][n + 1];
for (int i = 0; i < a.length; i++) {
a[i][0] = 1;
}
for (int i = 0; i < a[0].length; i++) {
a[0][i] = 1;
}
for (int i = 1; i < a.length; i++) {
for (int j = 1; j < a[i].length; j++) {
for (int k = 0; k <= j / book[i]; k++) {
int x = i - 1;
int y = j - k * book[i];
a[i][j] += a[x][y];
}
}
}
for (int i = 1; i <= n; i++) {
System.out.println(i + " --> " + a[book.length - 1][i]);
}
for (int j = 0; j < a[0].length; j++) {
System.out.print(j + " ");
}
System.out.println();
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
}
运行结果一 | 运行结果二 |
---|---|
这里首先对运行结果做一下解释:
- 9可取成,1 * 5 + 4 * 1;
- 以及,9 * 1,共2种。
- 10可取成,2 * 5;
- 以及,1 * 5 + 5 * 1;
- 以及,10 * 1;
- 以及,1 * 10,共4种。
所有乘号前面的是个数,乘号后面的是可取的硬币,这里可取的硬币有{ 1,5,10,25 }
- book数组的意思是:我们有几个硬币
- n:要凑多少数
- 二维数组a是:用来存放我们的过程,以及结果,也是一个初始化
接下来进行过程讲解
- 首先对数组的第一行和第一列进行初始化,且都为1,因为所有所有的数字,用1的话,都只有一种方式,就是都取1;而当要取的数字是0的时候,也只有一种方式,就是啥都不取。
- 这里有3层循环,第一层和第二层循环分别是行和列,i同时也表示现在扫描的是哪个硬币,j也表示现在需要凑的数量是多少。
- 然后讲下第三层for循环k,k可以理解为取几个硬币,然后看循环的判断式:k <= j / book[i];而取的硬币数目是小于等于这一列除以现在扫描到的哪个硬币,这里可以看下图👇
比如我们这里求的是14个硬币,有多少种组合方式,我把结果用橙色的底色标出来了,然后一种是当k=0的时候,也就是不取10,那么下标y不变,还是14,然后x坐标是这个橙色点的上一位,也就是3,把这位+=后,我们再继续循环,当k=1的时候,也就是说我们取了1个10,那么这个时候,还剩多少个数字要凑呢?答案是4个,也就是拿j-10=4,得到了y的值为4,而x还是1,也就是拿5去凑4,这个情况是我们之前已经算出来的了,这个值是1,那么我们再让之前加上的3去+1,那么再对k++,但是这个时候,如果取2个10的话,那么已经超出14了,所以就退出k这个循环。那么我这里为什么不标注在最后一行呢?因为25已经超出14了,所以取不到14。
再看一个例子
这里我就进行简单的表述了,我们要求的是橙色的框框,从右到左的3个蓝色框框,分别是k=0到k=2时候的值,也就是不取10,和取1个10以及2个10.