1
votes

Toutes les sommes exactes possibles à partir de plusieurs tableaux

On m'a posé le problème suivant et mon code est devenu un désordre horrible et je suis assez coincé.

On vous donne une allocation à dépenser dans certains magasins (quelque chose comme 15 $, juste un entier positif) Vous ne pouvez dépenser cet argent que sous deux conditions:

1) Vous achetez exactement un article dans chaque boutique.

2) Vous dépensez tout votre argent (il ne reste rien et aucune dette)

Trouvez toutes les façons possibles d'acheter des articles pour satisfaire ce qui précède.

En réalité, vous disposez d'un budget int et d'un tableau comme

9 et [[1,2,3], [0,5], [2,3,8]]

où chaque tableau interne répertorie les prix des articles dans une boutique. Il peut y avoir arbitrairement de nombreux magasins avec arbitrairement de nombreux articles. Les coûts ne peuvent pas être négatifs, mais ils peuvent être gratuits!

La solution attendue ici serait:

[[1,5,3], [2,5,2], [1,0,8]]

Comme chaque tableau contient un article de chaque boutique, chacun totalise 9, et toutes les possibilités sont présentes. Pour compliquer les choses, la vitesse est primordiale.

Voici mon code qui est tombé dans la folie et un manque presque complet de fonctionnalités:

def Stepper(bud,LOL):
    n=len(LOL)
    lasts=[]
    indices=[0 for j in range(n)]
    focus=0
    funds=[0 for j in range(n+1)]
    funds[0]=bud
    sols=[]
    moveable=[]
    for j in range(n):
        length=len(LOL[j])
        if(length==0):
            return []
        lasts.append(length-1)
        if(moveable==[]):
            if(length==1):
                funds[j+1]=funds[j]-LOL[j][0]
            else:
                moveable.append(j)
                focus=j
    while(moveable!=[]):
        while(LOL[focus][indices[focus]] > funds[focus]):
            indices[focus]+=1
        if(indices[focus]==lasts[focus]):
            if(moveable[-1]==focus):
                moveable.remove(focus)
            if(moveable==[]):
                if(focus<n-1):
                    moveable.append(focus+1)
        funds[focus+1]=funds[focus]-LOL[focus][indices[focus]]
        #print(n,lasts,indices,focus,moveable,funds,sols)
        if((funds[focus+1]!=0) and (focus<n-1)):
                focus+=1
                indices[focus]=0
        else:
            if(funds[focus+1]==0):
                for j in range(focus+1,n):
                    indices[j]=lasts[j]
                sols.append(list(indices))
            if(moveable[-1]==n-1):
                moveable.remove(n-1)
            if(moveable!=[]):
                focus=moveable[-1]
                indices[focus]+=1
                if(indices[focus]==lasts[focus]):
                    if(moveable[-1]==focus):
                        moveable.remove(focus)
                    if(moveable==[]):
                        if(focus<n-1):
                            moveable.append(focus+1)
                funds[focus+1]=funds[focus]-LOL[focus][indices[focus]]
                focus+=1
                indices[focus]=0
    return(sols)

où bud est le budget et LOL est la liste des listes (les magasins et les prix)


1 commentaires

Salut, vous devez réaliser l'algorithme Tree Traversal Depth-first avec une vague du coin supérieur droit (premier prix du premier magasin) vers le bas à gauche (dernier prix du dernier magasin). Des principes communs bien décrits partout. En outre, les performances peuvent être considérablement augmentées en vérifiant le solde actuel (somme de tous les nœuds traversés) <= budget , donc quand il est dépassé, il vous suffit de sauter le parcours approfondi suivant qui ne peut pas être obtenu avec itertools.product.


4 Réponses :


-1
votes

Voici un moyen simple, et probablement inefficace, de le résoudre.

In [70]: s = [[1,2,3],[0,5],[2,3,8]]    
In [71]: n = 9
In [72]: for x in s[0]:
    ...:     for y in s[1]:
    ...:         for z in s[2]:
    ...:             if x+y+z == n:
    ...:                 print(x,y,z)
    ...:
1 0 8
1 5 3
2 5 2

À partir de la première boutique, pour n'importe quelle option, itérer sur la boutique suivante, puis à nouveau, pour n'importe quelle option du deuxième magasin, parcourez les options du magasin suivant. Faites la somme de tous les prix et vérifiez si la somme est égale à 9.


1 commentaires

Le nombre de boutiques est variable. Même en ignorant les problèmes d'efficacité, cette réponse ne prend en charge qu'un nombre fixe de magasins.



0
votes

Si vous êtes autorisé à utiliser itertools

(1, 0, 8)
(1, 5, 3)
(2, 5, 2)

Sortie:

import itertools
x =  [[1,2,3],[0,5],[2,3,8]]
combinations = list(itertools.product(*x))
for o in combinations:
    if sum(o) == 9:
        print(o)

Dépend de cette question.


0 commentaires

1
votes

C'est un problème de combinatoire. Quel article de la boutique 1 se combine avec quel article de la boutique 2 et quels articles uniques des boutiques 3 ... n ajouter à un certain nombre?

La bibliothèque standard de Python a une fonction qui peut générer toutes ces combinaisons pour vous, vous épargnant les boucles for imbriquées. C'est le itertools.product a >:

>>> list(filter(lambda prices: sum(prices) == budget, itertools.product(*shops))
[(1, 0, 8), (1, 5, 3), (2, 5, 2)]

Ensuite, nous voulons nous débarrasser de toutes les combinaisons qui ne satisfont pas à notre condition (que les prix correspondent exactement au budget total). Utilisons la fonction filter intégrée pour obtenir notre solution:

>>> import itertools
>>> budget = 9
>>> shops = [[1, 2, 3], [0, 5], [2, 3, 8]]
>>> list(itertools.product(*shops))
[(1, 0, 2),
 (1, 0, 3),
 (1, 0, 8),
 (1, 5, 2),
 (1, 5, 3),
 (1, 5, 8),
 (2, 0, 2),
 (2, 0, 3),
 (2, 0, 8),
 (2, 5, 2),
 (2, 5, 3),
 (2, 5, 8),
 (3, 0, 2),
 (3, 0, 3),
 (3, 0, 8),
 (3, 5, 2),
 (3, 5, 3),
 (3, 5, 8)]


0 commentaires

0
votes

Si vous êtes toujours intéressé par un algorithme, voici ma solution:

Stepper(9, [[1,2,3],[0,5],[2,3,8]])

Pour le tester, appelez simplement

def Stepper(bud, shops, combinations = None):
    if combinations is None:
        combinations = [[item] for item in shops[0]] 
        #if empty, populate  the list of combinations with list containing every item of the first shop
        shops = shops[1:] #remove the shop from the list

    if len(shops) == 1: #if only one shop remains
        counter = 0
        while counter < len(combinations):
            comb = combinations[counter] # take a combination
            diff = bud - sum(comb)       # check how much you have to spend
            if diff in shops[0]: 
                #if the shop have what you're looking for you keep the combination
                comb.append(diff)
                counter += 1
            else:
                # there is no way to spend all the money
                combinations.remove(comb)

        return combinations

    new_combinations = list()
    for old_combination in combinations:
        for item in shops[0]:
            comb = old_combination + [item] #create every possible combination mixing the old combinations with the items of the next stop
            if sum(comb) < bud: new_combinations.append(comb) # the combination is valid only if you have 0 or more money left
    return Stepper(bud,shops[1:],new_combinations) # calculate combinations with the remaining shops


0 commentaires