赞
踩
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]; } }
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; } }
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; } }
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]; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。