Algorithme et optimisation

On considère le problème suivant :
on a différents objets de poids divers que l’on veut ranger dans un certain nombre de contenants ayant une capacité limitée.
Par exemple, on a 8 objets de poids respectifs 7,6,3,4,8,5,9,2 que l’on veut ranger dans des cartons dont la capacité est de 11 kg maximum.
On veut évidemment, si possible :
– ranger tous les objets,
– minimiser le nombre de cartons nécessaires.

Exemple 1

Exercice 1

Proposer différents algorithmes en langage « naturel ».
Pour chaque algorithme, déterminer l’invariant, le variant et préciser si la condition d’arrêt est vérifiée.
Tester vos algorithmes avec les 3 exemples.
Vos algorithmes permettent-ils d’obtenir une solution optimale ?

Exemple 2
Exemple 3

Exercice 2

Implémenter en Python vos différents algorithmes.
On utilisera des listes pour simuler les poids des objets et le rangement obtenu par l’algorithme.
Par exemple :

>>> poids=[6,5,5,3,3,2]
>>> rangement1_poids(12,3) # fonction avec un paramètre poids maximal et le nombre de carton
[[6,5],[5,3,2],[3]]

correspondra à la solution :

solution non optimale

Trouver la solution optimale à l’exemple 3.

Proposition de correction

Une proposition de correction avec 3 algorithmes :
– une algorithme de rangement totalement aléatoire : on tire un poids au hasard que l’on range dans une boîte disponible au hasard,
– un algorithme de rangement ordonné : on prend les poids au fur et à mesure et on les range dans la 1ere boîte disponible,
– un algorithme glouton sur le principe de « on range d’abord les poids les plus lourds dans la première boîte disponible ».

from random import randint

def creation_boites(nombre,poids_max):
    '''
    creation d'une liste de longueur n+1,
    les n premiers éléments représentent une boite
    le dernier élément représente la val max par boite
    retour : une liste
    >>> boites=creation_boites(6,12)
    >>> boites==[[], [], [], [], [], [], 12]
    True
    '''
    boites=[[] for i in range(nombre)]
    boites.append(poids_max)
    return boites

def boite_dispo(indice,val):
    '''
    indique si la boite correspondante à l'indice peut accueillir la val 
    sans dépasser le poids max
    >>> boites=[[5,2], [9], [], [], [], [], 12]
    >>>  boite_dispo(0,5)
    True
    >>> boite_dispo(1,5)
    False
    >>> boite_dispo(10,5)
    False
    '''
    global boites
    if indice>=len(boites):
        return False
    if sum(boites[indice])+val>boites[-1]:
        return False
    return True

    
def indice_boite_aleatoire(val):
    '''
    détermine l'indice d'une boîte aléatoire pouvant
    accueiller la valeur val, revoie False si aucune boîtes
    n'est dispo
    return : int ou False
    '''
    global boites
    boites_dispo=[]
    poids_max=boites[-1]
    for i in range(len(boites)-1):
        if boite_dispo(i,val)!=False:
            boites_dispo.append(i) 
    if len(boites_dispo)==0:
        return False
    else :
        indice_alea=randint(0,len(boites_dispo)-1)
        return int(boites_dispo[indice_alea])

def algo_on_range_au_hasard(a_ranger):
    '''
    principe : on prend une valeur à ranger au hasard,
    on la range au hasard dans un boite disponible si
    il y en a une
    return : False si on ne peut pas ranger une valeur,
    sinon la liste boites avec les valeurs rangées aléatoriement
    effet de bord : modifie la liste boites
    '''
    global boites
    val_a_ranger=a_ranger.copy()
    while len(val_a_ranger)>0 :
        # on tire une valeur à ranger au hasard
        val=val_a_ranger[randint(0,len(val_a_ranger)-1)]
        # on cherche à la ranger aléatoirement
        ind_alea=indice_boite_aleatoire(val)
        # on teste si l'indice est un entier
        # ind_alea!=False ne fonctionne pas pour
        # ind_alea=0 ( False = 0 )
        if type(ind_alea)==int:
            boites[ind_alea].append(val)
        else:
            print("Je n'ai pas pu ranger tous vos éléments.")
            return False
        # on supprime la valeur rangée de la liste
        # des valeurs à ranger
        val_a_ranger.remove(val)
    return boites
        
def algo_on_range_les_poids_successivement(a_ranger):
    '''
    principe : on prend les valeurs à ranger dans l'ordre au fur
    et à mesure, on les range dans la 1ere boite disponible
    return : False si on ne peut pas ranger une valeur,
    sinon la liste boites avec les valeurs rangées
    effet de bord : modifie la liste boites
    >>> a_ranger=[11,12,8,1,5,4,3,7]
    >>> boites=[[], [], [], [], [], 13]
    >>> algo_on_range_les_poids_successivement(a_ranger)
    >>> boites==[[11, 1], [12], [8, 5], [4, 3], [7], 13]
    True
    '''
    
    global boites
    for i in range(len(a_ranger)):
        indice=0
        while boite_dispo(indice,a_ranger[i])==False:
            indice+=1
            if indice==len(boites)-1:
                print("Je n'ai pas pu ranger vos valeurs")
                return False
        boites[indice].append(a_ranger[i])
    return boites

def rangement_par_poids_max(a_ranger):
    '''
    principe : on prend les valeurs à ranger par ordre décroissant au fur
    et à mesure, on les range dans la 1ere boite disponible
    return : False si on ne peut pas ranger une valeur,
    sinon la liste boites avec les valeurs rangées
    effet de bord : modifie la liste boites
    >>> a_ranger=[11,12,8,1,5,4,3,7]
    >>> boites=[[], [], [], [], [], 13]
    >>> algo_on_range_les_poids_successivement(a_ranger)
    >>> boites==[[12,1], [11], [8,5], [7,4], [3], 13]
    True
    '''
    global boites
    a_ranger.sort()
    a_ranger.reverse()
    for i in range(len(a_ranger)):
        indice=0
        while boite_dispo(indice,a_ranger[i])==False:
            indice+=1
            if indice==len(boites)-1:
                print("Je n'ai pas pu ranger vos valeurs")
                return False
        boites[indice].append(a_ranger[i])
    return boites
    
    
    
a_ranger=[11,12,8,1,5,4,3,7]
boites=creation_boites(5,13)
print("Algo aléatoire")
print("A ranger",a_ranger)
print("dans",boites)
algo_on_range_au_hasard(a_ranger)
print(boites)

print("Algo par parcours des listes")
boites=creation_boites(5,13)
print("A ranger",a_ranger)
print("dans",boites)
algo_on_range_les_poids_successivement(a_ranger)
print(boites)

print("Algo par parcours des listes")
boites=creation_boites(5,13)
print("A ranger",a_ranger)
print("dans",boites)
rangement_par_poids_max(a_ranger)
print(boites)