動態規劃--找零錢有多少種方法

問題: 給定數組arr,arr中的所有的值都爲正數且不重複。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim代表要找的錢數,求換錢有多少種方法。

分析:arr長度爲N,生成行數爲N,列數爲aim+1的矩陣dp。dp[i][j]的含義是在使用arr[0]…arr[i]貨幣的情況下,組成錢數j的方法數。


  1. 如果完全不用arr[i]貨幣,只使用arr[0]…arr[i-1]貨幣時,方法數爲dp[i-1][j]。
  2. 如果用1張arr[i]貨幣,剩下的錢使用arr[0.......i-1]貨幣組成,方法數爲dp[i-1][j-1*arr[i]]。
  3. 如果用2張arr[i]貨幣,剩下的錢使用arr[0......i-1]貨幣組成,方法數爲dp[i-1][j-2*arr[i]]。
  4. 如果用3張arr[i]貨幣,剩下的錢使用arr[0......i-1]貨幣組成,方法數爲dp[i-1][j-3*arr[i]]。
  5. ……......................

dp[i][j]的值即爲上述所有值得累加和。

求每一個位置都需要枚舉,時間複雜度爲O(aim)。dp一共有N*aim個位置,所以總的時間複雜度爲O(N*aim^2)

具體實現如下:

package basic_sork;

//找零錢---動態規劃方法
public class dp_find_money_way2 {
	public static void main(String[] args){
		int[] array={1,5,2};
		int aim=10;
		System.out.print(coins(array,aim));
	}
	public static int coins(int[] arr,int aim){
		//申明arr.lenght,aim+1的數組
		int[][] dp=new int[arr.length][aim+1];
		for(int i=0;i<arr.length;i++){
			dp[i][0]=1;//第一列爲1
		}
		for(int j=1;j<=aim;j++){
			if(j%arr[0]==0){
				dp[0][j]=1;//第一行中能夠被arr[0]整除的數,即可以被換錢,記爲1
			}else{
				dp[0][j]=0;
			}
		}
		for(int i=1;i<arr.length;i++){
			for(int j=1;j<=aim;j++){
				int temp=0;
				for(int k=0;k*arr[i]<=j;k++){
					temp+=dp[i-1][j-k*arr[i]];//累加用k張arr[i]貨幣後dp[i-1]中組成剩下錢數的方法數
				}
				dp[i][j]=temp;
			}
		}
		return dp[arr.length-1][aim];
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章