硬币拼凑(01背包和完全背包)
有n1+n2种面值的硬币,其中前n1种为普通币,可以取任意枚,后n2种为纪念币, 每种最多只能取一枚,每种硬币有一个面值,问能用多少种方法拼出m的面值?
输入描述:
第一行输入三个整数n1,n2,m n1,n2<=1000 m<=100000
第二行输入n1个整数表示普通币的面值
第三行输入n2个整数表示纪念币的面值
不同的硬币面值可能相同
输出描述:
使用编号不同但面值相同的硬币算不同的拼法
输出用多少种方法拼出m的面值,由于答案过大,对1e9 + 7取模

第一个问题:只考虑币数组,拼成指定钱数,有多少种方法
dp[i][j]:0...i 自由选,搞定j元有多少种方法
普遍位子如何填:
1:i号币我不用,->dp[i-1][j]
2:i号币我用,->dp[i-1][j-str[i]]
dp[i][j]=1+2


/**
dp[i][j]任意使用0---i号币,能组成j的钱来
【1,3,2,4】 8
dp[N-1][j]最事一行的意义是任意使用n个币,能组成的j钱
*/
public static long[][] getDpOne(int[] arr,int money) {
if (arr == null || arr.length == 0) {
return null;
}
long[][] dp = new long[arr.length][money + 1];
for (int i = 0; i < arr.length; i++) {
dp[i][0] = 1;
}
if (arr[0] <= money) {
dp[0][arr[0]] = 1;
}
for (int i = 1; i < arr.length; i++) {
for (int j = 1; j <= money; j++) {
dp[i][j] = dp[i - 1][j];
dp[i][j] += j - arr[i] > 0 ? dp[i - 1][j - arr[i]] : 0;
//输出用多少种方法拼出m的面值,由于答案过大,对1e9 + 7取模
dp[i][j] = dp[i][j] % 1000000007;
}
}
return dp;
}
第二个问题:只考虑券数组,拼成指定钱数,有多少种方法,每张券可以无限取

券在0....3上任意选,可以搞定100的方法数

dp[i][j]:券在0....i上任意选,可以搞定j的方法数

/**
dp[i][j]任意使用0---i号币(可以使用任意张),能组成j的钱来
【1,3,2,4】 8
dp[N-1][j]最事一行的意义是任意使用n个币,能组成的j钱
*/
public static long[][] getDpArb(int[] arr,int money){
if(arr==null||arr.length==0){
return null;
}
long[][] dp=new long[arr.length][money+1];
for(int i=0;i<arr.length;i++){
dp[i][0]=1;
}
for(int j=1;arr[0]*j<=money;j++){
dp[0][arr[0]*j]=1;
}
for(int i=1;i<arr.length;i++){
for(int j=1;j<=money;j++){
dp[i][j]=dp[i-1][j];
dp[i][j]+=j-arr[i]>=0?dp[i][j-arr[i]]:0;
dp[i][j]=dp[i][j]%100000007;
}
}
return dp;
}
原问题:
有n1+n2种面值的硬币,其中前n1种为普通币,可以取任意枚,后n2种为纪念币, 每种最多只能取一枚,每种硬币有一个面值,问能用多少种方法拼出m的面值?
public static long moneyWays(int[] arbitrary,int[] onlyOne,int money){
if(money<0){
return 0;
}
if((arbitrary==null ||arbitrary.length==0)
&& (onlyOne==null || onlyOne.length==0)){
return money==0?1:0;
}
//任意张的数组,一张的数组,不可能都没有
long[][] dparb=getDpArb(arbitrary,money);
long[][] dpone=getDpOne(onlyOne,money);
if(dparb==null){
return dpone[onlyOne.length-1][money];
}
if(dpone==null){
return dparb[arbitrary.length-1][money];
}
long res=0;
for(int i=0;i<=money;i++){
res+=dparb[dparb.length-1][i] * dpone[dparb.length-1][money-i];
res=res%1000000007;
}
return res;
}

浙公网安备 33010602011771号