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;ifor(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);

    }

}

(完)

你可能感兴趣的:(算法分析与设计,算法)