尝试为一般的硬币变化问题编写DP解决方案,该问题还记录了使用哪些硬币。到目前为止,我已经努力为我提供所需的最少数量的硬币,但无法弄清楚如何使用哪些硬币和多少次。我尝试使用值设置另一个表(布尔值),如果使用硬币但似乎无法正常工作。 有什么想法吗?
public static int minChange(int[] denom, int changeAmount)
{
int m = denom.length;
int n = changeAmount + 1;
int[][] table = new int[m][n];
boolean[][] used = new boolean[m][n];
for (int j = 0; j < n; j++)
table[m - 1][j] = j;
for (int i = 0; i < m; i++)
table[i][0] = 0;
for (int i = m-2; i >= 0; i--) //i denotes denominationIndex
{
for (int j = 1; j < n; j++) //j denotes current Amount
{
if (denom[i] > j)
{
table[i][j] = table[i+1][j];
//used[i][j] = false;
}
else
{
table[i][j] = Math.min(1 + table[i][j-denom[i]], table[i+1][j]);
/*Trying table for used coins
if (1 + table[i][j-denom[i]] < table[i+1][j])
used[i][j] = true;
else
used[i][j] = false;
*/
}
}
}
}
答案 0 :(得分:3)
试试这个解决方案,它只使用 O(M)内存并具有 O(N * M)复杂度:
public static int[] minChange(int[] denom, int changeAmount)
{
int n = denom.length;
int[] count = new int[changeAmount + 1];
int[] from = new int[changeAmount + 1];
count[0] = 1;
for (int i = 0 ; i < changeAmount; i++)
if (count[i] > 0)
for (int j = 0; j < n; j++)
{
int p = i + denom[j];
if (p <= changeAmount)
{
if (count[p] == 0 || count[p] > count[i] + 1)
{
count[p] = count[i] + 1;
from[p] = j;
}
}
}
// No solutions:
if (count[changeAmount] == 0)
return null;
// Build answer.
int[] result = new int[count[changeAmount] - 1];
int k = changeAmount;
while (k > 0)
{
result[count[k] - 2] = denom[from[k]];
k = k - denom[from[k]];
}
return result;
}
答案 1 :(得分:2)
public static int minimumNumberOfWays(int []deno, int amount){
int dp[] = new int[amount+1];
dp[0]=0;
int []prevCoin = new int[amount+1];
for(int j=1;j<=amount;j++){
dp[j]=Integer.MAX_VALUE;
for(int i=0;i<deno.length;i++){
if(deno[i]<=j && (1+dp[j-deno[i]] < dp[j]) ){
dp[j]=1+dp[j-deno[i]];
prevCoin[j]=deno[i];
}
}
}
int result = dp[amount];
List<Integer> coinsAdded = new ArrayList<Integer>();
for(int i=amount;i>=1;){
coinsAdded.add(prevCoin[i]);
int j=i;
i=amount-prevCoin[i];
amount = amount - prevCoin[j];
}
Integer [] coins = coinsAdded.toArray(new Integer[coinsAdded.size()]);
System.out.println( Arrays.toString(coins));
答案 2 :(得分:0)
以下似乎适用于Python:
def g( A, n ) :
#
if A == [] or n == 0 or min(A) > n :
return []
#
else :
#
min_len = float( "inf" )
min_seq = None
#
for i, a in enumerate( A ) :
if a <= n :
#
tmp = [ a ] + g( A[:i] + A[i+1:], n-a )
#
if len( tmp ) < min_len :
min_seq = tmp
min_len = len( min_seq )
#
return min_seq
#
for i in xrange(20) :
#
A = list( nr.randint( 1, 10, 5 ) )
print A, g( A[:-1], A[-1] )
答案 3 :(得分:0)
您不需要dp的第一个维度。您可以使用只有一个维度的数组 - 所有使用过的硬币的总和。然后,您可以简单地为您的dp的每个状态存储上次使用的硬币的索引。我的意思是:
int[] dp = new int[n];
int[] usedCoin = new int[n];
for (int i=0; i < n; ++i) {
dp[i] = -1; // state not reached
usedCoin[i] = -1;
}
dp[0] = 0; // initial state -- we can have sum 0 without any coins
for (int coinId = 0; coinId < m; coinId++)
for (int sum = 0; sum + denom[coinId] < n; sum++) {
int newSum = sum + denom[coinId];
if (dp[newSum] == -1 || dp[newSum] > 1 + dp[sum]) {
dp[newSum] = 1 + dp[sum];
usedCoin[newSum] = coinId;
}
}
如果你想用最少量的硬币找到具体的分解,你可以这样做:
int sum = changeAmount;
System.out.println("The used coins are:");
while (usedCoin[sum] != -1) {
System.out.print(denom[ usedCoin[sum] ].toString() + " ");
sum -= denom[ usedCoin[sum] ];
}
答案 4 :(得分:0)
使用以下伪代码重建解决方案: -
solutionSet = []
i = denom.length-1
j = changeAmount
While(i>=0) {
if(1+table[i][j-denom[i]]<table[i+1][j]) {
solutionSet.add(denom[i])
j = j - denom[i]
}
i--
}
注意:除了存储解决方案之外,不需要在此处使用额外的内存
答案 5 :(得分:0)
public class CoinChange {
public static void main(String[] args) {
int[] coins = {1,2,10,5};
int amt = 37;
makeChange(coins, amt);
}
public static void makeChange(int[] coins, int amount){
//Sorting the coins
Arrays.sort(coins);
int n = coins.length - 1;
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
while(amount > 0)
{
if(coins[n] <= amount)
{
int val = 1;
if(map.containsKey(coins[n]))
{
val = map.get(coins[n]);
val = val+1;
}
map.put(coins[n], val);
amount = amount - coins[n];
}
else
{
n--;
}
}
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
System.out.println(entry.getKey() +":" + entry.getValue());
}
}
}
答案 6 :(得分:0)
public class CoinChange {
/**
* Get mini num of coins
*
* @param coinValues
* coins
* @param totalMoney
* total money
* @return
*/
public int coinNum(int[] coinValues, int totalMoney) {
List<Integer> coins = new ArrayList<Integer>();
coins.add(0);
for (int i = 1; i <= totalMoney; i++) {
int coin = nearestCoin(i, coinValues);
int coinNum = coins.get(i - coin) + 1;
coins.add(coinNum);
}
return coins.get(totalMoney);
}
/**
* Get the coin nearest to specified value.
*/
private int nearestCoin(int value, int[] coinValues) {
int res = 0;
int nearest = Integer.MAX_VALUE;
for (int coinValue : coinValues) {
if (coinValue <= value) {
int distance = value - coinValue;
if (distance < nearest) {
nearest = distance;
res = coinValue;
}
}
}
return res;
}
@Test
public void test() throws Exception {
int res = coinNum(new int[] { 1, 2, 3, 5, 11 }, 81);
System.out.println(res);
}
}
答案 7 :(得分:0)
/ * 硬币变化问题
输入规格: First Line期望金额 第二行预计硬币数量 第三行包含按面额升序排列的硬币 假定无限供应硬币
输出规格: 每个案例都显示最低面额硬币,然后是下一个最高面额。 病例由线分开 如果不能形成数量,则打印-1 注意:这不是DP解决方案 * /
#include<iostream>
using namespace std;
int *num,*coins,*maxC,n,amount,flag=0,stop=0;
int sum()
{
int i=0,j;
int sum=0;
for(i=0;i<n;++i)
for(j=0;j<num[i];++j)
sum+=coins[i];
return sum;
}
void print()
{
int i,j;
for(i=0;i<n;++i)
{
for(j=0;j<num[i];++j)
cout<<coins[i]<<" ";
}
cout<<endl;
}
void printNum()
{
int i;
for(i=0;i<n;++i)
cout<<num[i]<<" ";
cout<<endl;
}
void nextIter()
{
int i,j;
int stat=0;
//printNum(); //Remove the comment if you want to see the values of num array in every iteration
for(i=0;i<n;++i)
{
if(num[i]==0)
stat=1;
else
{
stat=0;
break;
}
}
if(stat)
{
stop=1;
return ;
}
for(i=n-1;i>=0;--i)
{
int dec=0;
if(num[i]==0)
{
dec=1;
num[i]=maxC[i];
}
else
{
--num[i];
return ;
}
}
}
int find()
{
while(!stop)
{
if(amount==sum())
{
flag=1;
print();
}
nextIter();
}
}
int main()
{
int i;
cout<<"\nEnter amount:";
cin>>amount;
cout<<"\nEnter number of coins:";
cin>>n;
coins=new int[n];
maxC=new int[n];//contains maximum number of each denomination required
num=new int[n];//contains current number of each denomination required
for(i=0;i<n;++i)
{
cin>>coins[i];
num[i]=maxC[i]=amount/coins[i];
}
find();
if(!flag)
cout<<"-1";
cout<<endl;
system("pause");
return 0;
}
答案 8 :(得分:0)
使用动态编程的解决方案::
public int coinchange2(ArrayList<Integer> A, int B) {
int[] dp = new int[B+1];
dp[0]=1;
for(int i=0;i<A.size();i++){
for(int j=A.get(i);j<=B;j++)
{
dp[j]=(dp[j]+dp[j-A.get(i)])%1000007;
}
}
return dp[B];
}