第七章 遞迴、DFS、剪枝、回溯等問題 ------------- 7.4 硬幣表示某個給定數值
一、題目:
假設我們有8種不同面值的硬幣{1,5,10,25},用這些硬幣組合構成一個給定的數值n。 例如n=100,那麼一種可能的組合方式為 100 = 2*25+5*5+2*10+5*1。 問總共有多少種可能的組合方式?
二、思路:
先來看看遞迴解法,看到這種題目,不要一上來就想著我怎麼來劃分任務,我怎麼把任務交給其他人去做。首先還是由簡單到複雜,先列舉一些簡單的情況,發現規律。因為涉及到動態改變的問題,多種組合的方式,我們可以先在紙上寫出幾個簡單的例子來進行分析,我們不妨寫出1-25這個區間看一下n = 1-25之間的組合方案。
1---1
2---1
3---1
4---1
5---2
6---2
7---2
8---2
9---2
10---4
11---4
12---4
13---4
14---4
15---6 ...
因為給出的n直接牽涉到能夠使用較大的面值 比如n = 15 它就不能夠使用25的面值,只能從10 5 1這三種面值來組合。比如n = 25 我們可以使用0個25的面值而剩下的由10 5 1來進行組合, 10 可以由使用10 5 1來組合, 5可以由 5 1來組合,比如n=100,我們可以使用0個25,剩下的100交給 10 5 1去湊,也可以使用1個25,那麼剩下的75也交給10 5 1去湊,也可以使用2個25,3個25,這樣基本就是遞迴的思路了。因為涉及到兩個變數在變化,我們可以在迴圈中使用遞迴來解決,其中遞迴的方法需要解決傳入的變數的問題:涉及到錢的數量和對應面值的變化所以需要傳入兩個變化的量到方法中。
再來看看遞推(迭代)解法,迭代解法主要就是下一步要做的事由上一步通過某種關係來決定。比如這裡種類數主要由兩個變數來決定,所以需要二維陣列來儲存,分別是1~n,以及能夠使用的哪些面值。每一個點儲存的是種數。而遞推解法的思路本質上是和遞迴一樣的,只是表達的方式不一樣而已。
三、程式碼:
public class 硬幣表示 {
public static void main(String[] args) {
int ways;
for (int i = 1; i < 6; i++) {
ways = countWays(i);
System.out.println(i + "---" + ways);
}
System.out.println("========================================");
for (int i = 1; i < 6; i++) {
ways = countWay1(i);
System.out.println(i + "---" + ways);
}
System.out.println("========================================");
for (int i = 1; i < 6; i++) {
ways = countWay2(i);
System.out.println(i + "---" + ways);
}
}
/**
* 遞推解法
*/
public static int countWay1(int n){
int [] coins = {1,5,10,25};
int [][] dp = new int[4][n+1]; // 前i種面值,組合出面值j
for(int i = 0;i<4;i++){
dp[i][0] = 1; // 湊出面值0,只有一種可能,第一列初始化為1
}
for(int j=0;j<n+1;j++){
dp[0][j] = 1; // 用1來湊任何面值都只有一種解法,第一行初始化為1
}
for (int i = 1; i < 4; i++) {
for (int j = 1; j < n+1; j++) {
for (int k = 0; k <= j/coins[i]; k++) {
dp[i][j] += dp[i-1][j-k*coins[i]];
}
}
}
return dp[3][n];
}
/**
* 遞推解法
*/
public static int countWay2(int n){
int[] coins = { 1, 5, 10, 25 };
int[] dp = new int[n + 1];
dp[0] = 1;
for (int i = 0; i < 4; i++) {
for (int j = coins[i]; j < n+1; j++) {
dp[j] = (dp[j]+dp[j-coins[i]]) % 1000000007;
}
}
return dp[n];
}
/**
* 遞迴形式
*/
public static int countWays(int n){
if (n<=0) {
return 0;
}
return countWaysCore(n,new int[]{1,5,10,25},3);
}
private static int countWaysCore(int n, int[] coins, int cur) {
if (cur==0) {
return 1;
}
int res = 0;
// 不選coins[cur]
// 要一個
// 要兩個......
// 迴圈遞迴 二分到多分支
for (int i = 0; i * coins[cur] <= n; i++) {
int shengyu = n - i * coins[cur];
res += countWaysCore(shengyu, coins, cur - 1);
}
return res;
}
}
四、結果:
相關文章
- 第七章 遞迴、DFS、剪枝、回溯等問題 ------------- 7.5 “逐步生成結果”之非數值型問題 (合法括號)遞迴
- 第七章 遞迴、DFS、剪枝、回溯等問題 ------------- 7.3 題解:機器人走方格問題遞迴機器人
- 數獨問題(DFS+回溯)
- 遞迴加回溯遞迴
- leetcode題解(遞迴和回溯法)LeetCode遞迴
- 請教一個切片遞迴賦值的問題遞迴賦值
- 回溯和遞迴實現迷宮問題(C語言)遞迴C語言
- c++迷宮問題回溯法遞迴演算法C++遞迴演算法
- 遞迴與回溯法遞迴
- 遞迴回溯相關遞迴
- Acwing166 數獨題解 - DFS剪枝最佳化
- 整數劃分(硬幣問題)(dp)
- 遞迴問題遞迴
- n皇后問題--回溯法,以DFS的方式搜尋
- 活字印刷 回溯剪枝
- 資料結構和演算法——遞迴-八皇后問題(回溯演算法)資料結構演算法遞迴
- 遞迴——深度優先搜尋(DFS)——以滑雪問題為例(自頂而下)遞迴
- 遞迴路徑問題遞迴
- 遞迴-*全排列問題遞迴
- 數字索引賦值給多個變數簡單表示式索引賦值變數
- 五大演算法程式碼模板(DFS 遞迴非遞迴都算上,是六個)演算法遞迴
- DFS剪枝最佳化策略
- 回溯問題
- 樹遞迴問題的求解遞迴
- hdu2048遞迴問題遞迴
- hdu2049遞迴問題遞迴
- 華為0821筆試第三題筆記-回溯+剪枝筆試筆記
- 函式表示式–遞迴函式遞迴
- 揹包問題的遞迴與非遞迴演算法遞迴演算法
- 遞迴中的遞推與迴歸以及返回值和函式儲存的問題(以階乘問題進行討論)遞迴函式
- 拋擲硬幣的領先問題
- 遞迴求解漢諾塔問題遞迴
- 遞迴解決全排列問題遞迴
- P1433 吃乳酪 (dfs+剪枝)
- 利用正規表示式判斷一個給定的字元是否是迴文字元
- 遞迴:逆波蘭表示式遞迴
- 回溯法求一個集合中和為定值的所有集合
- 迴文數問題