动态规划——换钱的最少货币数

题目:

  给定数组arr, arr中所有的值都为正数且不重复。每个值代表一中面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的最少货币数。

思路:

  如果arr的长度为N, 则生成一个行数为N, 列数为aim+1的动态规划表dp[N][aim+1], dp[i][j]的含义为:在可以任意使用arr[0...i]货币的情况下,组成j所需的最小张数。

  设: arr=[5,2,3,1] aim = 5

  1.dp[0..N-1][0]的值表示找钱数为0时需要的最少张数,所以全设为0。(矩阵的第一列)

     0 0 0 0 0 0

  dp= 0 0 0 0 0 0

     0 0 0 0 0 0

     0 0 0 0 0 0 

     2.dp[0][0...aim]的值表示只能使用arr[0]货币也就是5的情况下,找0 ,1,2,3,4,5的钱的情况下。其中无法找开的一律设为32位的最大值,记为max.

      0   max  max  max  max   1  

  dp=    0    

        0

      0

  3.剩下的位置依次从左到右,再从上到下计算。假设计算到(i,j)位置,dp[i][j]的值可能来自下面的情况:

    完全不使用当前货币arr[i]情况系的最少张数,即dp[i-1][j]的值

    只使用一张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-arr[i]]+1  其中 j-arr[i]的值为使用了一张arr[i]后,还需要找多少钱。 i-1是指使用arr[i]之前的钱来兑换

    只使用两张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-2*arr[i]]+2

    只使用三张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-3*arr[i]]+3

    所有情况中,取最小的纸张数。所以:

    dp[i][j] = min{dp[i-1][j],  dp[i-1][j-k*arr[i]]} + k   ==>

    dp[i][j] = min{dp[i-1][j], min{dp[i-1][j-x*arr[i]]+x (x >= 1)}}   ==>

     设x-1 = y  >= 0   ==> x = y +1代入得

    dp[i][j] = min{dp[i-1][j], min{dp[i-1][j-arr[i]-y*arr[i]+y+1 (y>=0)}}

    又因为min{dp[i-1][j-arr[i]-y*arr[i]+ y (y>=0)] =>

    dp[i][j-arr[i]] 因为其中 dp[i-1][j-y*arr[i]+y] = dp[i][j] 

 

    最终有:dp[i][j] = min{dp[i-1][j], dp[i][j-arr[i]+1]} 如果 j-arr[i] < 0,即发生越界。

    说明arr[i]太大了,用一张都会超出钱数j,所以令dp[i][j]=dp[i-1][j]即可。

    

  

           0   max  max  max  max     1  

  dp=    0    max     1  max  2  1

      0  max  1    1  2   1

      0  1    1    1   2  1

 

package chapter_4.solution3;

public class Solution_3 {

    public static void main(String[] args) {
        int[] arr = {5,2,3,1};
        int aim = 5;
        System.out.println(minConins1(arr, aim));
    }

    public static int minConins1(int[] arr, int aim){
        if(arr == null || arr.length == 0 || aim < 0){
            return -1;
        }
        int[][] dp = new int[arr.length][aim+1];
        int max = Integer.MAX_VALUE;
        //设置第一行
        for(int j=1; j <= aim; j++){
            dp[0][j] = max;
            if(j-arr[0] >= 0 && dp[0][j-arr[0]] != max ){
                dp[0][j] = dp[0][j-arr[0]] + 1;
            }
        }
        int left = 0;
        for(int i=1; i < arr.length; i++){
           for(int j=1; j <=aim; j++){
          left = max;
if(j-arr[i] >=0 && dp[i][j-arr[i]] != max){ left = dp[i][j-arr[i]] + 1; } dp[i][j] = Math.min(left, dp[i-1][j]); } } for(int i=0; i < arr.length; i++){ for(int j=0; j<= aim; j++){ System.out.print(dp[i][j] + " "); } System.out.println(); } return dp[arr.length-1][aim] != max ? dp[arr.length-1][aim] : -1; } }

 

posted @ 2017-01-21 17:08  huangyichun  阅读(4684)  评论(0编辑  收藏  举报