基本動態規劃之硬幣問題

硬幣問題

問題描述

假設有 1 元,3 元,5 元的硬幣若干(無限),如今須要湊出 11 元,問如何組合才能使硬幣的數量最少?java

問題分析

乍看之下,咱們簡單的運用一下心算就能解出須要 2 個 5 元和 1 個 1 元的解。固然這裏只是列出了這個問題比較簡單的狀況。當硬幣的幣制或者種類變化,而且須要湊出的總價值變大時,就很難靠簡單的計算得出結論了。貪心算法能夠在必定的程度上得出較優解,但不是每次都能得出最優解。算法

這裏運用動態規劃的思路解決該問題。按照通常思路,咱們先從最基本的狀況來一步一步地推導。數組

咱們先假設一個函數 d(i) 來表示須要湊出 i 的總價值須要的最少硬幣數量。函數

  1. i = 0 時,很顯然咱們能夠知道 d(0) = 0。由於不要湊錢了嘛,固然也不須要任何硬幣了。注意這是很重要的一步,其後全部的結果都從這一步延伸開來
  2. i = 1 時,由於咱們有 1 元的硬幣,因此直接在第 1 步的基礎上,加上 1 個 1 元硬幣,得出 d(1) = 1
  3. i = 2 時,由於咱們並無 2 元的硬幣,因此只能拿 1 元的硬幣來湊。在第 2 步的基礎上,加上 1 個 1 元硬幣,得出 d(2) = 2
  4. i = 3 時,咱們能夠在第 3 步的基礎上加上 1 個 1 元硬幣,獲得 3 這個結果。但其實咱們有 3 元硬幣,因此這一步的最優結果不是創建在第 3 步的結果上得來的,而是應該創建在第 1 步上,加上 1 個 3 元硬幣,獲得 d(3) = 1
  5. ...

接着就再也不舉例了,咱們來分析一下。能夠看出,除了第 1 步這個看似基本的公理外,其餘日後的結果都是創建在它以前獲得的某一步的最優解上,加上 1 個硬幣獲得。得出:code

d(i) = d(j) + 1blog

這裏 j < i。通俗地講,咱們須要湊出 i 元,就在湊出 j 的結果上再加上某一個硬幣就好了。io

那這裏咱們加上的是哪一個硬幣呢。嗯,其實很簡單,把每一個硬幣試一下就好了:class

  1. 假設最後加上的是 1 元硬幣,那 d(i) = d(j) + 1 = d(i - 1) + 1
  2. 假設最後加上的是 3 元硬幣,那 d(i) = d(j) + 1 = d(i - 3) + 1
  3. 假設最後加上的是 5 元硬幣,那 d(i) = d(j) + 1 = d(i - 5) + 1

咱們分別計算出 d(i - 1) + 1d(i - 3) + 1d(i - 5) + 1 的值,取其中的最小值,即爲最優解,也就是 d(i)test

最後公式:基礎

代碼示例

這裏用 Java 實現了基本的代碼:

public class CoinProblemBasicTest {

    private int[] d; // 儲存結果
    private int[] coins = {1, 3, 5}; // 硬幣種類

    private void d_func(int i, int num) {
        if (i == 0) {
            d[i] = 0;
            d_func(i + 1, num);
        }
        else {
            int min = 9999999; // 初始化一個很大的數值。當最後若是得出的結果是這個數時,說明湊不出來。
            for (int coin : coins) {
                if (i >= coin && d[i - coin] + 1 < min) {
                    min = d[i - coin] + 1;
                }
            }
            d[i] = min;

            if (i < num) {
                d_func(i + 1, num);
            }
        }
    }


    @Test
    public void test() throws Exception {
        int sum = 11; // 須要湊 11 元
        d = new int[sum + 1]; // 初始化數組

        d_func(0, sum); // 計算須要湊出 0 ~ sum 元須要的硬幣數量
        for (int i = 0; i <= sum; i++) {
            System.out.println("湊齊 " + i + " 元須要 " + d[i] + " 個硬幣");
        }
    }
}

結果以下:

湊齊 0 元須要 0 個硬幣
湊齊 1 元須要 1 個硬幣
湊齊 2 元須要 2 個硬幣
湊齊 3 元須要 1 個硬幣
湊齊 4 元須要 2 個硬幣
湊齊 5 元須要 1 個硬幣
湊齊 6 元須要 2 個硬幣
湊齊 7 元須要 3 個硬幣
湊齊 8 元須要 2 個硬幣
湊齊 9 元須要 3 個硬幣
湊齊 10 元須要 2 個硬幣
湊齊 11 元須要 3 個硬幣
相關文章
相關標籤/搜索