1. 程式人生 > >JAVA程式碼—演算法基礎:最少貨幣換錢問題求解(動態規劃)

JAVA程式碼—演算法基礎:最少貨幣換錢問題求解(動態規劃)

最少貨幣換錢問題求解(動態規劃)

問題:換錢問題
給定一個數組arraydemo,arraydemo中所有的值都為正數且不重複。
每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim代表要找的錢數,
求組成aim的最少貨幣數。

舉例:
arraydemo=[1,5,10,50,100],aim = 53
1張50元,再加上3張1元,可以組成53元;其它的找錢方案都要使用更多張的貨幣,所以返回4
arraydemo=[1,5,10,50,100],aim=0
不用任何貨幣就可以組成0元,返回0
arraydemo=[5,10,50,100],aim=2
根本無法組成2元,錢不能找開的情況下預設返回-1

使用動態規劃求解思想分析過程:

原問題的分析為,如果arraydemo長度為N,生成行數為N,列數為aim+1的動態規劃表的矩陣DP。
dp[i][j]的含義是,在可以任意使用 arraydemo[0…i]貨幣的情況下,組成j所需的最小張數。
據此,dp[i][j]的值可以按照如下方式進行計算:
1、dp[0..N-1][0] 的值,即DP矩陣中第一列的值,表示找的錢數為0時需要的最少張數。錢數為0時,不需要任何貨幣,所以全設定為0即可。
2、dp[0][0..aim-1]的值,即DP矩陣中第一行的值,表示只能使用arraydemo[0]貨幣的情況下,找某個錢數的最小張數。
例如:arraydemo[0]=5,那麼能找開的錢數為 5,10,15,……,所以令 dp[0][5]=1, dp[0][10]=2, dp[0][15]=3,…,第一行其它位置所代表的錢數一律找不開,所以一律設定為32為整數的最大值,標記為max。
3、剩下的位置依次從左到右,再從上到下計算。
假設計算到位置:(i,j),dp[i][j]的值可能有:
(1) 完全不使用當前貨幣arraydemo[i]情況下的最少張數,即dp[i-1][j]的值
(2)只使用1張當前貨幣arraydemo[i]情況下的最少張數,即 dp[i-1][j-arraydemo[i]]+1
(3)只使用2張當前貨幣arraydemo[i]情況下的最少張數,即 dp[i-1][j-2*arraydemo[i]]+2
(4)只使用3張當前貨幣arraydemo[i]情況下的最少張數,即 dp[i-1][j-3*arraydemo[i]]+3

所有的情況中,最終取張數最小的。所以,

dp[i][j] = min(dp[i-1][j-k*arraydemo[i]]+k(0<=k))
推匯出; dp[i][j]=min(dp[i-1][j],min(dp[i-1][j-x*arraydemo[i]]+x(1<=x)))
再推匯出:dp[i][j]=min(dp[i-1][j],min(dp[i-1][j-arraydemo[i]-y*arraydemo[i]]+y+1(0<=y)))

又有:
min(dp[i-1][j-arraydemo[i]-y*arraydemo[i]]+y(0<=y)) => dp[i][j-arraydemo[i]]
所以,最終有:
dp[i][j]=min(dp[i-1][j],dp[i][j-arraydemo[i]]+1)
如果: j-arraydemo[i]<0,即發生了越界,說明 arraydemo[i]太大,用一張都會超過錢數j,令 dp[i][j]=dp[i-1][j]即可。

package com.bean.algorithmexec;

public class ExchangeDemo {

    /*
     * 問題:換錢問題
     * 給定一個數組arraydemo,arraydemo中所有的值都為正數且不重複。
     * 每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim代表要找的錢數,
     * 求組成aim的最少貨幣數。
     * 
     * 舉例:
     * arraydemo=[1,5,10,50,100],aim = 53
     * 1張50元,再加上3張1元,可以組成53元;其它的找錢方案都要使用更多張的貨幣,所以返回4
     * arraydemo=[1,5,10,50,100],aim=0
     * 不用任何貨幣就可以組成0元,返回0
     * arraydemo=[5,10,50,100],aim=2
     * 根本無法組成2元,錢不能找開的情況下預設返回-1
     * 
     * */

    private static int exchangeWays(int[] arraydemo, int aim) {
        // TODO Auto-generated method stub

        if(arraydemo==null || arraydemo.length==0 || aim<0) {
            return -1;
        }

        int n=arraydemo.length;
        int max=Integer.MAX_VALUE;
        int[][] dp=new int[n][aim+1];
        for(int j=1;j<=aim;j++) {
            dp[0][j]=max;
            if(j-arraydemo[0]>=0 && dp[0][j-arraydemo[0]]!=max) {
                dp[0][j]=dp[0][j-arraydemo[0]]+1;
            }
        }

        int left=0;
        for(int i=1;i<n;i++) {
            for(int j=1;j<=aim;j++) {
                left=max;
                if(j-arraydemo[i]>=0 && dp[i][j-arraydemo[i]]!=max) {
                    left=dp[i][j-arraydemo[i]]+1;
                }
                dp[i][j]=Math.min(left, dp[i-1][j]);
            }
        }


        return dp[n-1][aim] != max? dp[n-1][aim]:-1;
    }   

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int arraydemo[]= {1,5,10,50,100};
        int aim=57;

        int answer= exchangeWays(arraydemo,aim);
        System.out.println("# ANSWER= "+answer);

    }

}

(完)