Code pour "tirage avec remise sans ordre"

Code pour "tirage avec remise sans ordre" - PHP - Programmation

Marsh Posté le 09-07-2018 à 14:58:14    

Bonjour à tous,
 
me voici confronté à un problème, je dois réaliser un code (PHP) afin d'avoir toutes les combinaisons possibles "tirage avec remise sans ordre"
 
Disons que j'ai 3 colonnes qui peuvent prendre une valeur de 0 à 5.
 
le résultat est donc le suivant :
 
0-0-0
0-0-1
0-0-2
0-0-3
...
0-1-1
0-1-2
 
 
Du coup comme l'ordre n'est pas pris en compte, 0-0-1 = 1-0-0 je ne sais pas comment le vérifier avec mon code.


---------------
Henriot Steven
Reply

Marsh Posté le 09-07-2018 à 14:58:14   

Reply

Marsh Posté le 09-07-2018 à 17:19:18    

Tu tries tes trois valeurs selon la valeur (1<2<3 etc) et ensuite tu peux comparer si tu as déjà cette combinaison.

Reply

Marsh Posté le 09-07-2018 à 17:21:35    

Bonjour,
 
Si tu changes ton format de donnée tu n'aura plus le soucis ...
Par exemple, un tableau de 6 cases où tu stockerais le nombre de chiffre dans une chaine
0-0-1 = 1-0-0 = 2-1-0-0-0-0 => Il y deux 0, un 1, zero 2, zero 3, zero 4 et zero 5.
 
0-3-1 = 3-0-1 = 1-1-0-3-0-0 => Il y un 0, un 1, zero 2, un 3, zero 4 et zero 5.
 
edit:  [:rttolivers] grillé par une solution plus simple


Message édité par dede_sav le 09-07-2018 à 17:22:21
Reply

Marsh Posté le 09-07-2018 à 19:22:50    

rat de combat a écrit :

Tu tries tes trois valeurs selon la valeur (1<2<3 etc) et ensuite tu peux comparer si tu as déjà cette combinaison.


 
Je ne suis pas sûr de comprendre ou alors j'ai du mal m'exprimer.
 
Ce que je souhaite c'est trouver toutes ces valeurs pour les mettre dans un tableaux.
et je dispose de 2 variables.
 
- le nombre de cases > p
- le nombre d'index par case > n
 
Disons p = 4 et n = 10
 
le résultat que je souhaite dans mon tableau sera celui la
 
0-0-0-0
0-0-0-1
0-0-0-2
.....
0-0-0-10
0-0-1-1
0-0-1-2
.....
10-10-10-10


---------------
Henriot Steven
Reply

Marsh Posté le 09-07-2018 à 20:44:44    

Bonjour,
 
Un petit peu d'observation (3 tirages avec remise, 4 possibilités par tirage) :
 
0 0 0    1 0 0    2 0 0    3 0 0
0 0 1    1 0 1    2 0 1    3 0 1
0 0 2    1 0 2    2 0 2    3 0 2
0 0 3    1 0 3    2 0 3    3 0 3
 
0 1 0    1 1 0    2 1 0    3 1 0
0 1 1    1 1 1    2 1 1    3 1 1
0 1 2    1 1 2    2 1 2    3 1 2
0 1 3    1 1 3    2 1 3    3 1 3
 
0 2 0    1 2 0    2 2 0    3 2 0
0 2 1    1 2 1    2 2 1    3 2 1
0 2 2    1 2 2    2 2 2    3 2 2
0 2 3    1 2 3    2 2 3    3 2 3
 
0 3 0    1 3 0    2 3 0    3 3 0
0 3 1    1 3 1    2 3 1    3 3 1
0 3 2    1 3 2    2 3 2    3 3 2
0 3 3    1 3 3    2 3 3    3 3 3
 
Le mieux étant de ne simplement pas générer les combinaisons en double, la solution devrait être assez simple après observation.  ;)

Message cité 1 fois
Message édité par MaybeEijOrNot le 09-07-2018 à 20:45:44

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 09-07-2018 à 20:57:58    

MaybeEijOrNot a écrit :

Bonjour,
 
Un petit peu d'observation (3 tirages avec remise, 4 possibilités par tirage) :
 
0 0 0    1 0 0    2 0 0    3 0 0
0 0 1    1 0 1    2 0 1    3 0 1
0 0 2    1 0 2    2 0 2    3 0 2
0 0 3    1 0 3    2 0 3    3 0 3
 
0 1 0    1 1 0    2 1 0    3 1 0
0 1 1    1 1 1    2 1 1    3 1 1
0 1 2    1 1 2    2 1 2    3 1 2
0 1 3    1 1 3    2 1 3    3 1 3
 
0 2 0    1 2 0    2 2 0    3 2 0
0 2 1    1 2 1    2 2 1    3 2 1
0 2 2    1 2 2    2 2 2    3 2 2
0 2 3    1 2 3    2 2 3    3 2 3
 
0 3 0    1 3 0    2 3 0    3 3 0
0 3 1    1 3 1    2 3 1    3 3 1
0 3 2    1 3 2    2 3 2    3 3 2
0 3 3    1 3 3    2 3 3    3 3 3
 
Le mieux étant de ne simplement pas générer les combinaisons en double, la solution devrait être assez simple après observation.  ;)


 
 
On voit bien effectivement, sauf qu'il en manque :D
 
210, 310 a vu d’œil  


---------------
Henriot Steven
Reply

Marsh Posté le 09-07-2018 à 21:02:22    

Tapco a écrit :

On voit bien effectivement, sauf qu'il en manque :D

 

210, 310 a vu d’œil

 


De quoi? Il ne manque rien, regarde mieux. En rouge, les doublons. J'ai quand même mis l'axe de symétrie en évidence...

 
Citation :

0 0 0    1 0 0    2 0 0    3 0 0
0 0 1    1 0 1    2 0 1    3 0 1
0 0 2    1 0 2    2 0 2    3 0 2
0 0 3    1 0 3    2 0 3    3 0 3

 

0 1 0    1 1 0    2 1 0    3 1 0
0 1 1    1 1 1    2 1 1    3 1 1
0 1 2    1 1 2    2 1 2    3 1 2
0 1 3   1 1 3    2 1 3    3 1 3

 

0 2 0    1 2 0    2 2 0    3 2 0
0 2 1    1 2 1    2 2 1    3 2 1
0 2 2    1 2 2    2 2 2    3 2 2
0 2 3    1 2 3    2 2 3    3 2 3

 

0 3 0    1 3 0    2 3 0    3 3 0
0 3 1    1 3 1    2 3 1    3 3 1
0 3 2    1 3 2    2 3 2    3 3 2
0 3 3    1 3 3    2 3 3    3 3 3

Message cité 1 fois
Message édité par MaybeEijOrNot le 09-07-2018 à 21:05:50

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 09-07-2018 à 21:19:49    

MaybeEijOrNot a écrit :


 
 
De quoi? Il ne manque rien, regarde mieux. En rouge, les doublons. J'ai quand même mis l'axe de symétrie en évidence...
 

Citation :

0 0 0    1 0 0    2 0 0    3 0 0
0 0 1    1 0 1    2 0 1    3 0 1
0 0 2    1 0 2    2 0 2    3 0 2
0 0 3    1 0 3    2 0 3    3 0 3
 
0 1 0    1 1 0    2 1 0    3 1 0
0 1 1    1 1 1    2 1 1    3 1 1
0 1 2    1 1 2    2 1 2    3 1 2
0 1 3   1 1 3    2 1 3    3 1 3
 
0 2 0    1 2 0    2 2 0    3 2 0
0 2 1    1 2 1    2 2 1    3 2 1
0 2 2    1 2 2    2 2 2    3 2 2
0 2 3    1 2 3    2 2 3    3 2 3
 
0 3 0    1 3 0    2 3 0    3 3 0
0 3 1    1 3 1    2 3 1    3 3 1
0 3 2    1 3 2    2 3 2    3 3 2
0 3 3    1 3 3    2 3 3    3 3 3



 
mal compris la réponse. Donc oui il y a toute les combinaisons. Oui il faut éviter de générer les doublons mais comment faire en PHP ?


---------------
Henriot Steven
Reply

Marsh Posté le 09-07-2018 à 21:50:46    

1- Comment ferais-tu pour générer toutes les combinaisons ?
2- Sur quels paramètres pourrais-tu jouer pour ne pas générer les combinaisons en trop ?
3- D'après les observations, quelle règle peux-tu établir à propos des paramètres afin de ne générer que les combinaisons uniques ?

Message cité 1 fois
Message édité par MaybeEijOrNot le 09-07-2018 à 21:51:34

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 09-07-2018 à 22:07:06    

MaybeEijOrNot a écrit :

1- Comment ferais-tu pour générer toutes les combinaisons ?


 
boucle, mais ça j'ai réussi.
 
 

MaybeEijOrNot a écrit :

1- Comment ferais-tu pour générer toutes les combinaisons ?
2- Sur quels paramètres pourrais-tu jouer pour ne pas générer les combinaisons en trop ?
3- D'après les observations, quelle règle peux-tu établir à propos des paramètres afin de ne générer que les combinaisons uniques ?


 
j'en suis ici, je ne sais pas comment éviter les doublons étant donné que l'ordre n'a pas d'importance. Et en vrai p peut monter jusqu'à 20 et n vers les 200.
Si je peux éviter de trouver les doublons pour éviter la perte de temps...


---------------
Henriot Steven
Reply

Marsh Posté le 09-07-2018 à 22:07:06   

Reply

Marsh Posté le 09-07-2018 à 22:54:25    

Tu ne fais pas qu'une boucle a priori, ou alors j'ai raté quelque chose, je pense que tu en fais plusieurs. Sur une boucle tu n'as que 3 paramètres :
- valeur initiale
- vitesse d'incrémentation
- valeur finale

 

Dans mon exemple, tu as 3 tirages donc 3 boucles imbriquées (de variables $i, $j et $k). Ces 3 variables peuvent prendre pour valeurs 0, 1, 2 ou 3.
Si tu regardes les tirages que j'ai écrit, on prend la première colonne, soit tous les tirages commençant par 0. On peut donc pour $i = 0, pendre $j et $k entre 0 et 3.
Mais pour $i = 1 il faut commencer à éliminer des valeurs. Toutes celles ayant $k = 0.
Puis pour $i = 2, on remarque qu'il faut éliminer les valeurs pour $k = 0 ou $k = 1, etc.

 

Par contre je ne sais si p est le nombre de tirages ou le nombre de valeurs possibles. Mais avec p = 20 et n = 200 il va peut-être falloir choisir une autre stratégie que les boucles imbriquées. Déjà parce que ton nombre de boucles est prédéfinie et qu'en plus tu exploses la complexité de ton algorithme.

 

Que cherches-tu à faire au final ?


Message édité par MaybeEijOrNot le 09-07-2018 à 22:55:35

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 10-07-2018 à 11:16:29    

j'ai essayé de faire des reset de mes $i, $j. quand j'arrive au max d'une colonne, je le remet à 0 puis je fait la colonne +1
 
je pense que la solution serait de faire une fonction récursif mais je n'ai pas encore trouvé le bon code pour ne pas perdre du temps à calculer les doublons...


---------------
Henriot Steven
Reply

Marsh Posté le 10-07-2018 à 11:41:26    

Aide pour ne pas générer les doublons : matrice triangulaire supérieure...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 10-07-2018 à 12:02:28    

Pour mon exemple :

Code :
  1. for($i=0; $i<4; $i++) {
  2.    for($j=0; $j<4; $j++) {
  3.       for($k=$i; $k<4; $k++) {
  4.          $combinaison = $i.'-'.$j.'-'.$k;
  5.       }
  6.    }
  7. }
 

Attention, cela se passe différemment entre un tirage impair et un tirage pair.
Si le nombre de tirages est variable il faut en effet passer par une fonction récursive car tu ne peux pas utiliser des boucles puisqu'elles doivent être écrites à l'avance.
Je te conseille de te faire des exemples comme le mien mais avec 4 tirages et avec 5 tirages pour bien comprendre. Ensuite il faudra transposer en fonction récursive.

 

Niveau 1 : boucles imbriquées
Niveau 2 : fonction récursive
Niveau 3 : fonction mathématique (pour descendre la complexité de l'algo mais cela dépend de ce que tu veux réellement faire au final)


Message édité par MaybeEijOrNot le 10-07-2018 à 12:03:12

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 10-07-2018 à 14:09:38    

j'aurais fait

Code :
  1. $i=0
  2. $j=$i
  3. $k=$j


 
Avec  

Code :
  1. $i=0
  2. $j=0
  3. $k=$i


ça donne :
 
$i=0,$j=0,$k=0->3

Code :
  1. 0 0 0
  2. 0 0 1
  3. 0 0 2
  4. 0 0 3


 
$i=0,$j=1,$k=0->3

Code :
  1. 0 1 0
  2. ...



---------------
oui oui
Reply

Marsh Posté le 10-07-2018 à 15:00:41    

Code :
  1. $z = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q'];
  2. $boucle = count($z) - 1;
  3. $i = $j = $k = $t = 0;
  4. for ($i = 0; $i <= $boucle; $i++) {
  5.   for ($j = $i; $j <= $boucle; $j++) {
  6.     for ($k = $j; $k <= $boucle; $k++) {
  7.       for ($l = $k; $l <= $boucle; $l++) {
  8.         echo $z[$i].'-'.$z[$j].'-'.$z[$k].'-'.$z[$l].'<br>';
  9.         $t ++;
  10.       }
  11.     }
  12.   }
  13. }
  14. echo '<hr>Total = ' . $t;


 
 
J'ai trouvé grâce à vos réponses !!!
Enfin déjà en code pas très propre...
 
Maintenant, il faut que je trouve comment faire ça avec une fonction récursive pour que ce soit valable pour n case.


---------------
Henriot Steven
Reply

Marsh Posté le 10-07-2018 à 18:22:34    

art_dupond a écrit :

j'aurais fait

Code :
  1. $i=0
  2. $j=$i
  3. $k=$j


 
Avec  

Code :
  1. $i=0
  2. $j=0
  3. $k=$i


ça donne :
 
$i=0,$j=0,$k=0->3

Code :
  1. 0 0 0
  2. 0 0 1
  3. 0 0 2
  4. 0 0 3


 
$i=0,$j=1,$k=0->3

Code :
  1. 0 1 0
  2. ...




 
Non.
 
J'ai écrit toutes les possibilités plus haut. En tenant compte de l'ordre, on est, dans mon exemple, à 64 combinaisons.
Grâce à la coloration des combinaisons, nous pouvons compter simplement les combinaisons uniques quand on ne prend pas en compte l'ordre soit 6x4 (en rouge) + 4x4 (en noir) = 24 + 16 = 40 combinaisons uniques.
 
Si on fait ce que je proposais, on obtient les 40 combinaisons suivantes :

Code :
  1. 0-0-0
  2. 0-0-1
  3. 0-0-2
  4. 0-0-3
  5. 0-1-0
  6. 0-1-1
  7. 0-1-2
  8. 0-1-3
  9. 0-2-0
  10. 0-2-1
  11. 0-2-2
  12. 0-2-3
  13. 0-3-0
  14. 0-3-1
  15. 0-3-2
  16. 0-3-3
  17. 1-0-1
  18. 1-0-2
  19. 1-0-3
  20. 1-1-1
  21. 1-1-2
  22. 1-1-3
  23. 1-2-1
  24. 1-2-2
  25. 1-2-3
  26. 1-3-1
  27. 1-3-2
  28. 1-3-3
  29. 2-0-2
  30. 2-0-3
  31. 2-1-2
  32. 2-1-3
  33. 2-2-2
  34. 2-2-3
  35. 2-3-2
  36. 2-3-3
  37. 3-0-3
  38. 3-1-3
  39. 3-2-3
  40. 3-3-3


 
Maintenant si on fait ce que tu proposes on obtient 20 combinaisons :

Code :
  1. 0-0-0
  2. 0-0-1
  3. 0-0-2
  4. 0-0-3
  5. 0-1-1
  6. 0-1-2
  7. 0-1-3
  8. 0-2-2
  9. 0-2-3
  10. 0-3-3
  11. 1-1-1
  12. 1-1-2
  13. 1-1-3
  14. 1-2-2
  15. 1-2-3
  16. 1-3-3
  17. 2-2-2
  18. 2-2-3
  19. 2-3-3
  20. 3-3-3


La combinaison 0-1-0 n'est pas générée par exemple, donc ça ne fonctionne pas.


---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 10-07-2018 à 18:29:31    

Tapco a écrit :

Code :
  1. $z = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q'];
  2. $boucle = count($z) - 1;
  3. $i = $j = $k = $t = 0;
  4. for ($i = 0; $i <= $boucle; $i++) {
  5.   for ($j = $i; $j <= $boucle; $j++) {
  6.     for ($k = $j; $k <= $boucle; $k++) {
  7.       for ($l = $k; $l <= $boucle; $l++) {
  8.         echo $z[$i].'-'.$z[$j].'-'.$z[$k].'-'.$z[$l].'<br>';
  9.         $t ++;
  10.       }
  11.     }
  12.   }
  13. }
  14. echo '<hr>Total = ' . $t;


 
 
J'ai trouvé grâce à vos réponses !!!
Enfin déjà en code pas très propre...
 
Maintenant, il faut que je trouve comment faire ça avec une fonction récursive pour que ce soit valable pour n case.


Comme tu es parti sur ce que proposais art_dupond, je doute que ça fonctionne...


---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 10-07-2018 à 19:54:35    

Code :
  1. $z = [0, 1, 2, 3];
  2. $boucle = count($z) - 1;
  3. $i = $j = $k = $t = 0;
  4. for ($i = 0; $i <= $boucle; $i++) {
  5.   for ($j = $i; $j <= $boucle; $j++) {
  6.     for ($k = $j; $k <= $boucle; $k++) {
  7.       echo $z[$i].'-'.$z[$j].'-'.$z[$k].'<br>';
  8.       $t ++;
  9.     }
  10.   }
  11. }


 
Résultat :
 

Code :
  1. 0-0-0
  2. 0-0-1
  3. 0-0-2
  4. 0-0-3
  5. 0-1-1
  6. 0-1-2
  7. 0-1-3
  8. 0-2-2
  9. 0-2-3
  10. 0-3-3
  11. 1-1-1
  12. 1-1-2
  13. 1-1-3
  14. 1-2-2
  15. 1-2-3
  16. 1-3-3
  17. 2-2-2
  18. 2-2-3
  19. 2-3-3
  20. 3-3-3
  21. Total = 20


 
ça fonctionne bien


---------------
Henriot Steven
Reply

Marsh Posté le 10-07-2018 à 21:04:44    

Ok, c'est moi qui n'est pas compris le problème. [:prozac]  
 
J'étais parti, je ne sais pas pourquoi, sur pas d'ordre gauche/droite et droite/gauche, donc en effet ça fonctionne en réduisant le nombre d'itération sur chaque boucle imbriquée. Et là ça simplifie grandement ton problème.


---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 10-07-2018 à 22:07:06    

MaybeEijOrNot a écrit :

Ok, c'est moi qui n'est pas compris le problème. [:prozac]  
 
J'étais parti, je ne sais pas pourquoi, sur pas d'ordre gauche/droite et droite/gauche, donc en effet ça fonctionne en réduisant le nombre d'itération sur chaque boucle imbriquée. Et là ça simplifie grandement ton problème.


 
 
plus qu'à adapter ça pour n case. Pour l'instant, toujours pas trouvé


---------------
Henriot Steven
Reply

Marsh Posté le 11-07-2018 à 11:18:02    

Tu peux faire un truc comme ça.

Code :
  1. $N = 4; # taille du set de données
  2. $C = 4; # nombre de colonnes
  3. echo 'Dataset size: '.$N.'<br />';
  4. echo 'Columns: '.$C.'<br />';
  5. echo '<hr />';
  6. # on initialise un tableau de résultat de dimension C : 0 0 0 ...
  7. $curr = array_fill(0,$C,0);
  8. # on se place sur la dernière valeur du tableau
  9. $rank = $C - 1;
  10. while (true) {
  11.   $new_rank = false;
  12.   # On affichage le résultat
  13.     foreach($curr as $val) {
  14.       echo $val;
  15.     }
  16.     echo '<br >';
  17.   # Si la première valeur de tableau de résultat est (N-1), alors on a fini.
  18.   if ($curr[0] == $N-1) {
  19.     break;
  20.   }
  21.   # On regarde si la valeur actuelle == (N-1)
  22.   # Si c'est le cas, on a fini d'incrémenter sur ce rang
  23.   #   => il faut descendre de rang ($rank--)
  24.   #
  25.   # On "descend" de rang tant que les valeurs rencontrées sont == N-1
  26.    while ($curr[$rank] == $N-1) {
  27.     $rank--;
  28.     $new_rank = true;
  29.   }
  30.  
  31.   # on incrémente la valeur au rang courrant
  32.   $curr[$rank]++;
  33.   # si on a changé de rang il faut mettre a jour tous les rangs supérieurs
  34.   # Les rangs supérieurs vont prendre la meme valeur que la valeur du rang courrant.
  35.   if ($new_rank) {
  36.     for($i=$rank+1;$i<$C;++$i) {
  37.       $curr[$i] = $curr[$rank];
  38.     }
  39.     # on remet le rang à droite pour recommencer à incrémenter à droite
  40.     $rank = $C - 1;
  41.   }
  42. }
 


L'idée c'est de créer un tableau de résultat et d'incrémenter les valeurs pour générer toutes les combinaisons.

 

Pour l'exemple à N=4 valeurs possibles et C=3 colonnes,
on va initialiser un tableau de resultats : 000

 

On va incrémenter la valeur la plus à droite jusqu'à atteindre la valeur MAX:
000
001
002
003

 

Quand celle-ci est atteinte, on incrémente la valeur du rang inférieur:
013

 

et on réinitialise toutes les valeurs "à droite" avec cette nouvelle valeur:
011

 

De nouveau, on incrémente jusqu'à atteindre la valeur MAX:
011
012
013

 


Lorsqu'on doit descendre de rang, on le fait jusqu'à trouver une valeur != MAX

 

Donc, si la valeur courante est 033, ça donne

 

1. Mise à jour du rang le plus à droite dont la valeur < MAX
133

 

2. Réinitialisation des valeurs à droite de cette valeur
111

 

3. On recommence à incrémenter à droite.


Message édité par art_dupond le 11-07-2018 à 11:20:24

---------------
oui oui
Reply

Marsh Posté le 12-07-2018 à 17:59:07    

C'est super, merci à tous. Ça fonctionne comme je veux.
 
J'ai plus qu'à adapter à mon code.


---------------
Henriot Steven
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed