算法:换钱的最少货币数

题目

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

输入

输入包括两行,第一行两个整数n(0<=n<=1000)代表数组长度和aim(0<=aim<=5000),第二行n个不重复的正整数,代表arr(1≤arri≤109)\left( 1 \leq arr_i \leq 10^9 \right)(1≤arri​≤109)。

输出

输出一个整数,表示组成aim的最小货币数,无解时输出-1.

先上代码:

import java.util.*;

public class Main{
    // dp[i][j] = min{dp[i-1][j],dp[i][j-arr[i]]+1} 
    public static int leastChangesCount(int[] nums,int aim) {
        if (nums == null || nums.length == 0 || aim < 0) {
            return -1;
        }
        int[][] dp = new int[nums.length][aim+1];
        int max = Integer.MAX_VALUE;
        for (int j = 1;j <= aim;j++) {
            dp[0][j] = max;
            if (j - nums[0] >= 0 && dp[0][j-nums[0]] != max) {
                dp[0][j] = dp[0][j-nums[0]] + 1;
            }
        }
        
        for (int i = 1;i < nums.length;i++) {
            for (int j = 1;j <= aim;j++) {
                if (j-nums[i] < 0 || dp[i][j-nums[i]] == max) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.min(dp[i-1][j],dp[i][j-nums[i]]+1);
                }
            }
        }
        return dp[nums.length-1][aim] != max ? dp[nums.length-1][aim] : -1;
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int length = scanner.nextInt();
        int aim = scanner.nextInt();
        int[] nums = new int[length];
        for (int i = 0;i < length;i++) {
            nums[i] = scanner.nextInt();
        }
        
        System.out.println(leastChangesCount(nums,aim));
    }
}

再聊思想:

这是一道经典的算法问题,首先我们用二维数组记录动态规划中的值 ,dp[i][j]表示的是使用数组前i种货币来换j块钱所用的最少货币数,接着我们来找递推式,显而易见,我们可以得到dp[i][j] = min{dp[i-1][j-nums[i]*k]}+k,k>=0,意思就是从只换k个第i种货币挑出来值最小的那个,接着递推:
dp[i][j] = min{dp[i-1][j],dp[i-1][j-nums[i]*m]+m},m>=1
=min{dp[i-1][j],dp[i-1][j-nums[i]*n-nums[i]]+n+1},n>=0,这里以n+1换元
=min{dp[i-1][j],dp[i][j-nums[i]]+1}
得到递推式之后,初始化dp数组,接着两层遍历就可以得到结果了

你可能感兴趣的:(算法,动态规划,算法)