• [程序员代码面试指南]递归和动态规划-换钱的最少货币数(DP,完全背包)


    题目描述

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

    解题思路

    • dp[i][j]表示只用第0到i种货币,凑成j元的最小货币张数。
    • 初始化第一行
    • 初始化中,无法凑成的初始化为Integer.MAX_VALUE-1否则+1会爆精度变为负数。

    转移方程:

    • dp[i][j]=min{dp[i-1]【j-k*arr[i]】+k} (k>=0)
    • 整理得 dp[i][j]=min{dp[i-1][j],min{dp[i-1]【j-k*arr[i]】+k}} (k>=1)
    • 变换得 dp[i][j]=min{dp[i-1][j],min{dp[i-1]【j-(y+1)*arr[i]】+(y+1)}} (y>=0)
    • 整理得 dp[i][j]=min{dp[i-1][j],min{dp[i-1]【j-arr[i]-y*arr[i]】+y+1}} (y>=0)
    • 变换得最终转移方程:
    dp[i][j]=min{dp[i-1][j],dp[i]【j-arr[i]】+1}    (j-arr[i]>=0)
    dp[i][j]=dp[i-1][j]      (j-arr[i]<0)
    

    含义上,即:用arr[0]-arr[i]的面值凑j的需要的最少张数=min{不用arr[i]凑j的最少张数,至少用一张arr[i]凑j-arr[i]的最少张数+1张}

    代码采用空间压缩,使用一维的dp数组。

    待做

    感觉是完全背包,与经典问题中各量的对应关系思考一下。

    代码

    public class Solution {
    	public int getCoinsCount(int arr[],int aim){
    		int[] dp=new int[aim+1];
    		
    		//initial
    		for(int j=0;j<=aim;++j) {
    			dp[j]=Integer.MAX_VALUE-1;//
            }
            for(int k=0;arr[0]*k<=aim;++k) {
                    dp[arr[0]*k]=k;
            }
    		
    		for(int i=1;i<arr.length;++i) {
    			for(int j=arr[i];j<=aim;++j) {
    				dp[j]=Math.min(dp[j], dp[j-arr[i]]+1);
    			}
    		}
    		
    		if(dp[aim]==Integer.MAX_VALUE-1) {
    			return -1;
    		}
    		else {
    			return dp[aim];
    		}
    	}
    }
    
  • 相关阅读:
    C++ 根据对象名字创建对象
    Google是如何测试的(一)
    lex yacc 学习
    C语言宏定义时#(井号)和##(双井号)的用法
    更多编译器对C++11的支持比较
    用C++11替代Boost的实验之三
    最先进的开源游戏引擎KlayGE 4.2发布
    各编译器对C++11的支持比较
    在Android模拟器上的一些小陷阱
    推出KlayGE Foundation Library
  • 原文地址:https://www.cnblogs.com/coding-gaga/p/10843717.html
Copyright © 2020-2023  润新知