問題: 給定數組arr,arr中的所有的值都爲正數且不重複。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim代表要找的錢數,求換錢有多少種方法。
分析:arr長度爲N,生成行數爲N,列數爲aim+1的矩陣dp。dp[i][j]的含義是在使用arr[0]…arr[i]貨幣的情況下,組成錢數j的方法數。
- 如果完全不用arr[i]貨幣,只使用arr[0]…arr[i-1]貨幣時,方法數爲dp[i-1][j]。
- 如果用1張arr[i]貨幣,剩下的錢使用arr[0.......i-1]貨幣組成,方法數爲dp[i-1][j-1*arr[i]]。
- 如果用2張arr[i]貨幣,剩下的錢使用arr[0......i-1]貨幣組成,方法數爲dp[i-1][j-2*arr[i]]。
- 如果用3張arr[i]貨幣,剩下的錢使用arr[0......i-1]貨幣組成,方法數爲dp[i-1][j-3*arr[i]]。
- ……......................
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];
}
}