当前位置:   article > 正文

几种换零钱的动态规划(动态规划也称动态优化,是求一个最优的解,比如最小的数或者最大的数)_换零钱的动态规划表

换零钱的动态规划表

1、换零钱

package dynamicPrograming;

import java.util.Scanner;

//题目:给定数组a,a中所有数均为正数,每一个值代表一种面值,且只有一张,再给定一个正整数aim代表要找的钱数,问有多少种不同的换钱方法。
//经典的动态规划方法都是将动态规划表建立起来,动态规划表均是n行aim+1列,首先确定表的边界的值(即第一行与第一列的值),再分析dp[i][j]的值。
//分析出:d[i][j]=d[i-1][j]+(j-a[i]?d[i-1][j-a[i]]:0)
//时间复杂度为O(n*aim) 空间复杂度 为O(n*aim)
public class ChangeMoney
{
	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		int n =sc.nextInt();
		int[] a =new int[n];
		for(int i=0;i<n;i++)
			{a[i]=i+1;
			System.out.print(a[i]+" ");
			}
		System.out.println();
		int m=sc.nextInt();
		System.out.println(numOfChange(a,m));
	}
	
	public static int numOfChange(int[] a,int aim) {
//	建立dp表。	
		int[][] dp = new int[a.length][aim+1];
		int n =a.length;
		System.out.println("n:"+n);
//	给出表的第一列 的值	; 第一列表示组成 0元的方法均数为一种,即 所有面值都不取
		for(int i =0;i<n;i++) {
			dp[i][0]=1;
					}
//	给出 表的第一行	的值(除第一列第一行以外,所以i从1开始)
		for(int i=1;i<aim+1;i++) {
			dp[0][i]=0;
			if(i==a[0]) {
				dp[0][i]=1;
			}
		}
//	给出 表的其他位置 的值	
		for(int i=1;i<n;i++)
		{
			for(int j=1;j<aim+1;j++)
				{
				dp[i][j]=dp[i-1][j];
				dp[i][j] += j-a[i]>=0 ? dp[i-1][j-a[i]]:0;
				}
		}
		
//		查看一下dp表:
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<aim+1;j++)
				{
				System.out.print(dp[i][j]+" ");
						
				}
			System.out.println();
		}
		
		return dp[n-1][aim];
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

2、换零钱

package dynamicPrograming;

import java.util.Scanner;

//题目:给一个数组,值都为正数且不重复,每个值代表一种面值的纸币,每种面值的纸币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的最少货币张数。不能组成返回-1.
public class ChangeMoney2
{
	public static void main(String[] args)
	{
//		输入再做一做,做成数组 靠控制台输入 aim 也是控制台输入
		int[] arr = {1,4,16,64};
		Scanner sc = new Scanner(System.in);
		int n=sc.nextInt();
		int aim = 1024;
		System.out.println(minCoin(arr,aim-n));
	}
	public static int minCoin(int[] arr,int aim) {
		if(arr==null||arr.length==0||aim<0) {
			return -1;
		}
		int n = arr.length;
		int max = Integer.MAX_VALUE;
		int[][] dp= new int [n][aim+1];
//		给dp矩阵的第一行赋值,第一列的值就全为0,不用改了,初始化就已经赋了0
		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 < n; 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]);
			}
		}
		return dp[n-1][aim] != max ? dp[n-1][aim]: -1;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3、换零钱

package dynamicPrograming;
//题目:给定数组arr。arr中所有的数全为正数,每个数代表一张钱的面值,再给一个整数aim,代表要换的钱数,求组成aim的最少货币张数
public class ChangeMoney3
{
	public static void main(String[] args)
	{
		int[] arr= {5,2,5,3};
		int aim =10;
		System.out.println(minCoin3(arr,aim));
	}
	public static int minCoin3(int[] arr,int aim) {
		if(arr==null||arr.length==0||aim<0) {
			return -1;
		}
		int n = arr.length;
		int max = Integer.MAX_VALUE;
		int[][] dp = new int[n][aim+1];
		for(int j=1;j<aim+1;j++) {
			dp[0][j] = max;
		}
		if(arr[0] <= aim) {
			dp[0][arr[0]] = 1;
		}
		int leftup = 0;
		for(int i =1;i < n;i++) {
			for(int j =1;j<=aim;j++) {
				leftup = max;
				if(j-arr[i] >= 0 && dp[i-1][j-arr[i]] != max) {
					leftup = dp[i-1][j-arr[i]]+1;
				}
				dp[i][j] = Math.min(leftup,dp[i-1][j]);
			}
		}
		return dp[n-1][aim] != max ? dp[n-1][aim] : -1;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

4、换零钱,空间优化:一维数组的更新

package dynamicPrograming;

import java.util.Scanner;

//对额外空间进行压缩,额外空间复杂度由O(n*aim)变为O(aim)
//原始dp表:d[i][j]=d[i-1][j]+(j-a[i]?d[i-1][j-a[i]]:0)
//按行更新:d[j]=d[j]+(j-a[i]>=0?d[j-a[i]]:0   表示此刻的值d[j]由上一行的值确定,
public class ChangeMoneyOptimization
{
	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		int n =sc.nextInt();
		int[] a =new int[n];
		for(int i=0;i<n;i++)
			{a[i]=i+1;
			System.out.print(a[i]+" ");
			}
		System.out.println();
		int m=sc.nextInt();
		System.out.println(numberOfChange(a,m));
	}
	public static int numberOfChange(int[] a,int aim) {
		int[] d=new int[aim+1];
//		对第一行赋值
		d[0]=1;
		for(int i=1;i<aim+1;i++)
			{
			d[i]=0;
			if(i==a[0]) {
				d[i]=1;
			}
			System.out.print(d[i]+" ");
			}
		System.out.println();
//	后面每行的值都是在前面的基础上进行更新
		for(int i=1;i<a.length;i++)
			{
//			for(int j=0;j<aim+1;j++)   (数组更新) 注意: 用j++,当j从小往大递增时,索引j-a[i]处的值可能已经被新的值覆盖了,造成错误。因此采用j从大往小递减。
			for(int j=aim;j>=0;j--)
				{d[j]=d[j]+(j-a[i]>=0?d[j-a[i]]:0);
				
				}
			
			}
		
		return d[aim];
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/243871
推荐阅读
相关标签
  

闽ICP备14008679号