硬幣找零問題

假如如今有四種硬幣類型:1角,2角,5角和1元。java

你如今是超市收銀員,老闆要求你每次都使用最少的硬幣給用戶找零。git

例如,用戶須要找零6角,你須要找給他 一個5角 + 一個1角,這樣只用到2個硬幣,而不是找給他 六個1角 或者 三個2角。github

面對這樣的問題咱們該如何思考呢?編程

 

假如當前已經選擇了 i-1 枚硬幣,當選擇下一枚硬幣 i 的時候,面對下面兩種狀況:數組

面對這兩種選擇咱們須要作的就是選擇其中的最優解。spa

下面以找零6角爲例進行一下推算。code

找零1角,可供選擇的硬幣爲1角,那此時的最優解在選擇這1角硬幣和不選擇這1角硬幣中。blog

 

狀況一:若是選擇這1角硬幣,這意味着須要的硬幣數量 = ((找零1角 - 當前硬幣金額 )所須要的硬幣數量 )+ 1ip

找零1角 - 當前硬幣金額 = 1 -1 = 0,而找零0角須要的硬幣數量爲0,因此第一種狀況須要的硬幣數量 = 0 + 1 = 1get

狀況二:若是不選擇這枚硬幣,這意味着須要的硬幣數量 = 以前 1 - 1 = 0 種硬幣找零1角的最有解。

咱們知道若是硬幣種類爲0,咱們是沒法進行找零的,也就是須要找零的硬幣爲無窮大。

 

顯然狀況一須要的硬幣數量更少。此時的最優解爲1。

同理咱們能夠推論出後面的結果。下圖顯示了這個推算過程。

 

如上推算所示,咱們在推演時須要考慮一些邊界條件:

 

一、若是當前沒有硬幣,是沒法找零的,也就是不管多少硬幣都沒法找零。

二、若是須要找零的金額爲0,那這時候也須要找零。

三、若是須要找零的金額數量小於硬幣的面額,那這枚硬幣就不須要使用。好比找零金額爲6角,那1元的硬幣確定是用不着的。

 

一、2 兩個邊界條件在找零錢前應該是默認成立的,因此在編寫程序的時候須要將它們設置爲初始條件。

邊界條件3則是在咱們找零過程當中須要進行判斷的,在編程時候應該寫在找零程序中。

好了,說了這麼多,仍是直接上代碼方便快捷= =

package com.lkb.dp.problems;

import java.util.Arrays;

/**
 * @Description 硬幣找零問題
 * 假設只有 1角,2角,5角,1元的硬幣,
 * 在超市結帳時,若是須要找零錢,收銀員但願將最少的硬幣數找給顧客。那麼,給定須要找的零錢數目,如何求得最少的硬幣數呢?
 * @Author lkb
 * @CreateDate: 2019/6/1
 */
public class ChargeProblem {

    public static void main(String[] args) {
        int[] coinsValues = {1,2,5,10};
        Arrays.sort(coinsValues);
        int n = 6;
        int minCoinsNumber = charge(coinsValues, n);
        System.out.println(minCoinsNumber);
    }


    /**
     * 功能描述: 硬幣找零問題
     * @author lkb
     * @date 2019/6/1
     * @param
     * @return int
     */
    public static int charge(int[] coinKind, int money){
        //這個數組保存最優解
        //例如  value[2][5] 表示 使用 coinKind[0] coinKind[1] coinKind[2] 找零 money = 5 的最優解
        int[][] value = new int[coinKind.length+1][money+1];

        //邊界條件1:若是硬幣類型爲0,則永遠找不到合適的硬幣找零 、
        // 這裏設置爲最大值是由於咱們後續比較使用
        for(int i=0; i<=money; i++){
            value[0][i] = Integer.MAX_VALUE;
        }
        //邊界條件2:若是錢爲0,則永遠找不到合適的硬幣找零
        for(int i=0; i<=coinKind.length; i++){
            value[i][0] = 0;
        }

        for(int mon=1; mon<=money; mon++){
            for(int kind=1; kind<=coinKind.length; kind++){
                //邊界條件2:若是硬幣金額大於錢,則最優解是 上一步的最優解
                if(coinKind[kind-1] > mon){
                    value[kind][mon] = value[kind-1][mon];
                    continue;
                }

                //當前最優解分爲兩種狀況,須要在下面兩種狀況選擇一種解最小的狀況
                //一個是使用了當前類型的硬幣,value[kind][mon - coinKind[kind-1]] + 1
                // 一個是沒有使用當前類型的硬幣, value[kind-1][mon]
                if((value[kind][mon - coinKind[kind-1]] + 1) < value[kind-1][mon]){
                    value[kind][mon] = value[kind][mon - coinKind[kind-1]] + 1;
                }else{
                    value[kind][mon] = value[kind-1][mon];
                }
            }
        }

        return value[coinKind.length][money];
    }


}

 

你們也能夠在這個地址下載源碼,或者關注個人公衆號,一塊兒見證個人成長。

相關文章
相關標籤/搜索