Étant donné une liste de notes des joueurs, je dois diviser les joueurs (c.-à-d. Les notes) en deux groupes aussi équitablement que possible. L'objectif est de minimiser la différence entre la note cumulée des équipes. Il n'y a aucune contrainte quant à la façon dont je peux diviser les joueurs en équipes (une équipe peut avoir 2 joueurs et l'autre équipe peut avoir 10 joueurs).
Par exemple: [5, 6, 2, 10, 2, 3, 4]
devrait revenir([6, 5, 3, 2], [10, 4, 2])
Je voudrais connaître l'algorithme pour résoudre ce problème. Veuillez noter que je prends un cours d'introduction à la programmation en ligne, donc des algorithmes simples seraient appréciés.
J'utilise le code suivant, mais pour une raison quelconque, le vérificateur de code en ligne dit qu'il est incorrect.
def partition(ratings):
set1 = []
set2 =[]
sum_1 = 0
sum_2 = 0
for n in sorted(ratings, reverse=True):
if sum_1 < sum_2:
set1.append(n)
sum_1 = sum_1 + n
else:
set2.append(n)
sum_2 = sum_2 + n
return(set1, set2)
Mise à jour: J'ai contacté les instructeurs et on m'a dit que je devrais définir une autre fonction "d'aide" à l'intérieur de la fonction pour vérifier toutes les différentes combinaisons, puis je dois vérifier la différence minimale.
Réponses:
Remarque: modifié pour mieux gérer le cas lorsque la somme de tous les nombres est impaire.
Le retour en arrière est une possibilité pour ce problème.
Il permet d'examiner toutes les possibilités de manière récursive, sans avoir besoin d'une grande quantité de mémoire.
Il s'arrête dès qu'une solution optimale est trouvée:,
sum = 0
oùsum
est la différence entre la somme des éléments de l'ensemble A et la somme des éléments de l'ensemble B. EDIT: il s'arrête dès quesum < 2
, pour traiter le cas où la somme de tous les nombres est impair, c'est-à-dire correspondant à une différence minimale de 1. Si cette somme globale est paire, la différence min ne peut pas être égale à 1.Il permet de mettre en œuvre une procédure simple d' abandon prématuré :
à un instant donné, s'il
sum
est supérieur alors la somme de tous les éléments restants (c'est-à-dire non placés en A ou B) plus la valeur absolue du minimum actuel obtenu, alors on peut renoncer le chemin actuel, sans examiner les éléments restants. Cette procédure est optimisée avec:Voici un pseudo-code
Initialisation:
a[]
sum_back[i] = sum_back[i+1] + a[i];
min_diff = sum_back[0];
a[0]
dans A -> l'indicei
de l'élément examiné est mis à 1up_down = true;
: ce booléen indique si nous allons actuellement en avant (vrai) ou en arrière (faux)Boucle while:
Si (up_down): avant
sum_back
sum
selon ce choixif (i == n-1)
: LEAF -> teste si la valeur optimale est améliorée et retourne si la nouvelle valeur est égale à 0 (EDIT:)if (... < 2)
; aller à l'arrièreSi (! Updown): en arrière
i == 0
: retoursum
valeurVoici un code, en C ++ (Désolé, je ne connais pas Python)
la source
if I == 0
. Je l'ai testé en remplaçant 10 par 11 dans votre exempleJe pense que vous devriez faire le prochain exercice par vous-même, sinon vous n'apprenez pas beaucoup. Quant à celui-ci, voici une solution qui tente de mettre en œuvre les conseils de votre moniteur:
Production:
Notez que cette sortie est différente de celle désirée, mais les deux sont correctes.
Cet algorithme est basé sur le fait que, pour sélectionner tous les sous-ensembles possibles d'un ensemble donné avec N éléments, vous pouvez générer tous les entiers avec N bits et sélectionner le I-ème élément en fonction de la valeur du I-ème bit. Je vous laisse ajouter quelques lignes afin de vous arrêter dès que le
best_distance
zéro est nul (car ça ne peut pas aller mieux, bien sûr).Un peu sur les bits (notez que
0b
c'est le préfixe d'un nombre binaire en Python):Un nombre binaire:
0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57
Décalé à droite de 1:
0b0111001 >> 1 == 0b011100 == 28
Décalé à gauche de 1:
0b0111001 << 1 == 0b01110010 == 114
Décalé à droite de 4:
0b0111001 >> 4 == 0b011 == 3
Au niveau du bit
&
(et):0b00110 & 0b10101 == 0b00100
Pour vérifier si le 5e bit (index 4) est 1:
(0b0111001 >> 4) & 1 == 0b011 & 1 == 1
Un suivi de 7 zéros:
1 << 7 == 0b10000000
7 unités:
(1 << 7) - 1 == 0b10000000 - 1 == 0b1111111
Toutes les combinaisons 3 bits:
0b000==0
,0b001==1
,0b010==2
,0b011==3
,0b100==4
,0b101==5
,0b110==6
,0b111==7
(note que0b111 + 1 == 0b1000 == 1 << 3
)la source
L'algorithme suivant fait cela:
a
, impair dans la listeb
pour commencera
etb
si le changement est pour le mieuxJ'ai ajouté des instructions d'impression pour montrer les progrès de votre liste d'exemples:
Production:
la source
Comme je sais que je dois générer toutes les listes possibles, je dois créer une fonction "d'aide" pour aider à générer toutes les possibilités. Après cela, je vérifie la différence minimale et la combinaison de listes avec cette différence minimale est la solution souhaitée.
La fonction d'assistance est récursive et vérifie toutes les possibilités de combinaisons de listes.
Exemples
r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2]
:, la partition optimale serait:([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])
avec une différence de1
.r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70]
, la partition optimale serait:([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])
avec une différence de0
.la source
Voici un exemple assez élaboré, destiné à des fins éducatives plutôt qu'à des performances. Il présente quelques concepts Python intéressants tels que les compréhensions de listes et les générateurs, ainsi qu'un bon exemple de récursivité dans lequel les cas marginaux doivent être vérifiés de manière appropriée. Les extensions, par exemple seules les équipes avec un nombre égal de joueurs sont valides, sont faciles à mettre en œuvre dans les fonctions individuelles appropriées.
Production:
la source
Étant donné que vous voulez même des équipes, vous connaissez le score cible des notes de chaque équipe. Il s'agit de la somme des notes divisée par 2.
Le code suivant devrait donc faire ce que vous voulez.
Production
Il y a d'autres divisions qui ont le même,
fairness
elles sont toutes disponibles pour trouver à l'intérieur du tuple strong_ratings, je choisis simplement de regarder la première car cela existera toujours pour toute liste de notes que vous transmettez (fournielen(ratings) > 1
).la source
Une solution gourmande pourrait donner une solution sous-optimale. Voici une solution assez simple et gourmande, l'idée est de trier la liste par ordre décroissant afin de diminuer l'effet de l'ajout de notes dans le bucket. La note sera ajoutée à ce compartiment dont la somme totale des notes est inférieure
Production :
Éditer:
Une autre approche consistera à générer tous les sous-ensembles possibles de la liste. Disons que vous avez l1 qui est l'un des sous-ensembles de la liste, alors vous pouvez facilement obtenir la liste l2 telle que l2 = list (original) - l1. Le nombre de tous les sous-ensembles possibles de la liste de taille n est 2 ^ n. On peut les désigner comme seq d'un entier de 0 à 2 ^ n -1. Prenons un exemple, disons que vous avez list = [1, 3, 5] alors aucune combinaison possible n'est 2 ^ 3 soit 8. Maintenant, nous pouvons écrire toutes les combinaisons comme suit:
Solution:
Production :
la source