1

Il y a beaucoup de questions et de réponses sur le changement de pièces mais je ne trouve pas celle-ci et je me demande même si c'est un problème de monnaie.Changement de pièces, programmation dynamique, mais réduction de la valeur de la pièce après la première utilisation

Fondamentalement, j'ai un tas de pièces différentes, et une quantité infinie de chaque pièce.

Ainsi, disons qu'il existe des piles de différentes dénominations. Chaque pile est infinie. (Donc nombre infini de pièces 25c, nombre infini de pièces 2c etc).

Cependant, au-dessus de chaque pile de pièces est une pièce spéciale qui a une valeur supérieure (ou égale) aux pièces ci-dessous. Je ne peux pas accéder aux pièces ci-dessous sans utiliser cette pièce sur le dessus.

Ce que j'essaie de déterminer, c'est le nombre minimum de pièces nécessaires pour faire une certaine somme.

Je pense que c'est une programmation dynamique résoluble mais je ne sais pas comment ajouter cette limitation aux solutions traditionnelles. Je me demandais si je devais simplement enlever la pièce spéciale dans ma liste une fois que je l'utilise et la remplacer par les pièces normales, mais je ne peux pas sembler raisonner si cela casserait l'algorithme ou pas.

+0

Il est essentiellement le changement de pièce DP. Vous devriez travailler une pile de pièces à la fois, avec une mise à jour de DP légèrement plus compliquée. –

+0

Au moment où je pense à calculer les pièces minimales pour chaque valeur de 0 jusqu'à la somme (comme la solution traditionnelle). Pour ce faire, je vérifie chaque pile, en itérant sur une liste de piles L. Si je trouve que la somme des sommes est complétée en utilisant la pièce spéciale d'une pile. Je vais remplacer cette pièce spéciale par la pièce régulière (dans la liste L), et ça restera comme ça pour toujours. – Eric

Répondre

0

Cela ressemble à un problème de programmation dynamique classique, où le défi consiste à choisir l'état correctement.

Habituellement, nous choisissons la somme des pièces sélectionnées comme état de problème, et le nombre de pièces sélectionnées comme valeur d'état. Les transitions sont toutes les pièces que nous pouvons prendre. Si nous avons des pièces 25c et 5c, nous pouvons passer de l'état Sum à la valeur Count aux états Sum+25,count+1 et Sum+5,count+1.

Pour votre limitation, l'état devrait être augmenté avec des informations sur les pièces spéciales (en haut) qui ont été prises. Donc vous ajoutez un peu pour chaque pile de pièces de monnaie. Ensuite, vous avez juste besoin de définir les transitions possibles de chaque état. C'est simple: si un bit pour la pile est positionné, cela signifie que la pièce supérieure a déjà été prise et que vous pouvez ajouter une pièce non-supérieure de cette pile à la somme des états, en gardant tous les bits identiques. Sinon, vous pouvez prendre la pièce supérieure de cette pile, ajouter sa valeur à la somme d'état et définir le bit associé.

Vous démarrez à partir de l'état avec la somme 0, tous les bits sont effacés et la valeur 0, puis les états de construction de la somme la plus basse jusqu'à la cible. A la fin, vous devriez itérer sur toutes les combinaisons possibles de bits et. comparez les valeurs de l'état avec la somme cible et la combinaison de bits. Choisissez le minimum - ce serait la réponse.

Exemple code solution:

#Available coins: (top coin value, other coins value) 
stacks = [(17,8),(5,3),(11,1),(6,4)] 
#Target sum 
target_value = 70 

states = dict() 
states[(0,0)] = (0,None,None) 
#DP going from sum 0 to target sum, bottom up: 
for value in xrange(0, target_value): 
    #For each sum, consider every possible combination of bits 
    for bits in xrange(0, 2 ** len(stacks)): 
     #Can we get to this sum with this bits? 
     if (value,bits) in states: 
      count = states[(value,bits)][0] 
      #Let's take coin from each stack 
      for stack in xrange(0, len(stacks)):     
       stack_bit = (1 << stack)     
       if bits & stack_bit: 
        #Top coin already used, take second 
        cost = stacks[stack][1] 
        transition = (value + cost, bits) 
       else: 
        #Top coin not yet used 
        cost = stacks[stack][0] 
        transition = (value + cost, bits | stack_bit) 
       #If we can get a better solution for state with sum and bits 
       #update it 
       if (not (transition in states)) or states[transition][0] > count + 1: 
        #First element is coins number 
        #Second is 'backtrack reference' 
        #Third is coin value for this step 
        states[transition] = (count+1, (value,bits), cost) 

min_count = target_value + 1 
min_state = None 
#Find the best solution over all states with sum=target_value 
for bits in xrange(0, 2 ** len(stacks)): 
    if (target_value,bits) in states: 
     count = states[(target_value,bits)][0] 
     if count < min_count: 
      min_count = count 
      min_state = (target_value, bits) 
collected_coins = [] 
state = min_state 
if state == None: 
    print "No solution" 
else: 
    #Follow backtrack references to get individual coins 
    while state <> (0,0): 
     collected_coins.append(states[state][2]) 
     state = states[state][1] 
    print "Solution: %s" % list(reversed(collected_coins)) 
+0

Désolé, je pensais avoir compris mais en réalité je ne l'ai pas fait.Je ne comprends pas très bien votre dernier paragraphe, est-il possible de développer ce qui se passe entre le deuxième et le dernier paragraphe? Par exemple, en essayant de trouver la somme 10 avec cette pile: 6 (5) 3 (2) Au moment où mon problème est que j'ai pris une pièce (6) pour faire la somme 6 et marqué cette pile prise (pile est devenue 5). Au total 10 deux de ces 5 ont été utilisés. Sum 6 n'a pas été utilisé dans le cadre de la solution. Donc, je suis évidemment manquant cette itération sur toutes les parties possibles? – Eric

+0

@Eric, peut-être que le code peut l'expliquer mieux? – deniss

+0

Oui, merci pour l'effort! C'est logique - avoir des exigences supplémentaires ajoute certainement plus de complexité au temps que je pensais pour commencer. – Eric

0

La solution ci-dessous est basée sur deux faits 1) nombre infini de pièces dans toutes les dénominations disponibles

Algorithm:- 

Let Given number be x 

call the below method repeatedly until you reach your coin value, 
Each time of iteration pass the remaining value to be assigned with coins and also the coin denomination 

Method which will receive the number and the coin value 
Parameters: x - coin to be allocated 
      z - value of coin 
if(x > z) { 
    integer y = x/z * z 
    if(y == x) { 
     x is divisible by z and hence allocate with x/z number of coins of z value. 
} 
    if(Y != x) { 
     x is not a multiple of z and hence allocate with x/z number of coins from z cents value and then for remaining amount repeat the same logic mentioned here by having the next greatest denomination of 
    coin. 

    } 
} 
else if(x < z) { 
    return from this method; 
} 
else if(x == z) { 
    x is divisible by z and hence allocate with x/z number of coins of z value  
} 


Example iteration: 

Given number = 48c 
Coins denomination: 25c, 10c, 5c, 2c, 1c 

First Iteration: 

Parameter x = 48c and z = 25c 
return value would be a map of 1 coin of 25c, [25c , 1] 
calculate the remaining amount 48c - 25c = 23c 
23c is not equal to zero and not equal to 1 continue the loop. 

Second Iteration: 

Parameter x = 23c and z = 10c 
return value would be a map of 2 coins of 10c, [10c, 2] 
calculate the remaining amount 23c - 20c = 3c 
3c is not equal to zero and not equal to 1 continue the loop. 

Third Iteration: 

Parameter x = 3c and z = 5c 
No coins allocated 
3c is not equal to zero and not equal to 1 continue the loop. 

Fourth Iteration: 

Parameter x = 3c and z = 2c 
return value would be a map of 1 coin of 2c, [2c, 1] 
Remaining amount 3c - 2c = 1c 
Remaining amount Equals to 1 add an entry in map [1c, 1] 


Final Map Entries: 

[25c, 1] 
[10c, 2] 
[2c, 1] 
[1c, 1] 
[1c, 1] 
+0

L'algorithme Greedy ne fonctionne pas pour ce problème. Le contre-exemple est x = 29, pièces de monnaie = {20, 14, 1}. L'optimum est 3 = 2 * 14,1 * 1. Solution Greedy est 10 = 1 * 20,9 * 1 – deniss

+0

@Deniss - Oui, vous avez raison –