Petit probleme de denombrement

Petit probleme de denombrement - Algo - Programmation

Marsh Posté le 23-05-2008 à 21:41:09    

voila, j'ai 3 sets : I,O,M
chacun de ces ses peut contenir entre 0 et N éléments sous la contrainte suivante :
N(I)+N(O)+N(M) = C
ou C est une constante entière.
ex :
C = 3
Combo possibles  
I O M
3 0 0
0 3 0
0 0 3
2 1 0
2 0 1
1 2 0
0 2 1
0 1 2
1 0 2
1 1 1
 
soit 10 combinaisons
 
Je voudrais savoir combien de combinaison de set j'ai en fonction de C  et un chtit algo pr tous les générer tous.
Voila

Reply

Marsh Posté le 23-05-2008 à 21:41:09   

Reply

Marsh Posté le 23-05-2008 à 22:08:41    

Je procederais ainsi:
1) se ramener au cas d'une suite decroissante de 3 entiers
Ici tu vas avoir
3 0 0
2 1 0
1 1 1
2) faire les permutations:
Si trois valeurs egales, on ne fait rien
si deux valeurs egales
permutations circulaires seulement
Si aucune valeur egale
les permutation circulaires et les transpositions de 2 elts (bref, les elts du groupe symmetrique S3 autres que l'identité)
3 0 0 -> 0 0 3 (permutation circulaire)
3 0 0 -> 0 3 0 (permutation circulaire²)
..........................................................
2 1 0 -> 1 0 2 (permutation circulaire)
2 1 0 -> 0 2 1 (permutation circulaire²)
2 1 0 -> 1 2 0 (transposition elts de tete)
2 1 0 -> 0 1 2 (transposition elt initial et final)
2 1 0 -> 2 0 1 (transposition elts de queue)
.............................................................
1 1 1 identiques: on ne fait rien
 
A+,


Message édité par gilou le 23-05-2008 à 22:09:50

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 23-05-2008 à 22:33:25    

Empiriquement (testé pour C = 0..8) il semble que l'on aie le nombre de combinaisons de set comme valant (C+1)(C+2)/2
A+,


Message édité par gilou le 23-05-2008 à 22:34:12

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 23-05-2008 à 22:44:40    

oui je viens de trouver (C+1)(C+2)/2 ^^
Pour l'algo, je m'attendais à qqchose d eplus regulier. La je fait betement une triple boucle dans la quelle je test si i+o+m = C avec une astuce dans le decompte de depart de o et m. Je vais voir à utiliser tes astuces ;)
En fait, mon but est de generer les (C+1)(C+2)/2 en exactement (C+1)(C+2)/2 iterations

Reply

Marsh Posté le 23-05-2008 à 22:58:31    

En exactement (C+1)(C+2)/2 iterations ca ne me semble pas particulierement evident.
Dans ce que je donnais, il y a beaucoup moins de tours de boucle, les generations par permutation et transposition ayant lieu a l'interieur d'un même tour de la triple boucle.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 23-05-2008 à 23:06:37    

oui je vois.
Le problème ensuite va être de transformer ça en code à base de BOOST_PP_ XD

Reply

Marsh Posté le 23-05-2008 à 23:47:07    

En fait, on n'a pas une triple boucle, mais une double boucle.
Le premier terme, i, varie en décroissant de C a [C/3]+ ou [X]+ note la partie entiere superieure de X
Le second terme, j, varie en décroissant de Min(C-i, i) a Min(C-i, [(C-i)/2]+)  [cette expression complexe, c'est pour dire que ca varie en décroissant de Min(C-i, i) a  [(C-i)/2]+ sauf quand i = C auquel cas j = 0]
et ca nous fournit les triplets ordonnés (i, j, C-i-j)
A+,


Message édité par gilou le 23-05-2008 à 23:48:15

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-05-2008 à 00:58:55    

Me suis amusé a en coder un proto rapide en perl pour tester l'algo:
Passer la valeur de C sur la ligne de commande pour le faire marcher.
 

Code :
  1. #!/usr/bin/perl
  2. use warnings;
  3. use strict;
  4. #calcul des bornes de la premiere boucle
  5. my $C = $ARGV[0]; # C est donne sur la ligne de commande
  6. my $tiers_de_C = entsupmod($C, 3);
  7. for (my $i = $C; $i >= $tiers_de_C; --$i) {
  8.     #calcul des bornes de la seconde  boucle
  9.     my $sup = minimum($i, $C-$i);
  10.     my $inf = entsupmod($C-$i, 2);
  11.     $inf = minimum($inf, $C-$i);
  12.     for (my $j = $sup; $j >= $inf; --$j) {
  13.         my $k = $C - ($i + $j);
  14.         print "($i, $j, $k)\n";
  15.         if ($i == $j) {
  16.             if ($j != $k) {
  17.                 print "($k, $i, $j)\n";
  18.                 print "($j, $k, $i)\n"; 
  19.             }
  20.         }
  21.         else {
  22.             print "($k, $i, $j)\n";
  23.             print "($j, $k, $i)\n";
  24.             if ($j != $k) {
  25.                 print "($k, $j, $i)\n";
  26.                 print "($i, $k, $j)\n";
  27.                 print "($j, $i, $k)\n";
  28.             }
  29.         }
  30.     }
  31. }
  32. #calcul de la partie entiere superieure du quotient des deux arguments
  33. sub entsupmod {
  34.     use integer; #la division sera entiere
  35.     my $num = shift;
  36.     my $mod = shift;
  37.     return (($num%$mod)?(($num/$mod)+1):($num/$mod));
  38. }
  39. sub minimum {
  40.     my $a = shift;
  41.     my $b = shift;
  42.     return (($a<$b)?$a:$b);
  43. }


 
A+,


Message édité par gilou le 24-05-2008 à 01:15:59

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-05-2008 à 08:52:11    

On dira ce qu'on veut, mais Prolog est quand même plus concis :

decoupe(X, I, J, K) :-
   between(0, X, I),
   between(0, X, J),
   K is X - I - J,
   K >= 0.
 
test(N) :-
   setof((X,Y,Z), decoupe(N, X,Y,Z), L),
   writeln(L).


Message édité par Trap D le 24-05-2008 à 08:55:06
Reply

Marsh Posté le 24-05-2008 à 10:03:53    

Plus concis certes, mais beaucoup moins optimal, puisque tu fais une double boucle qui fait C*C itérations.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-05-2008 à 10:03:53   

Reply

Marsh Posté le 24-05-2008 à 10:09:39    

Joel F a écrit :

voila, j'ai 3 sets : I,O,M
chacun de ces ses peut contenir entre 0 et N éléments sous la contrainte suivante :
N(I)+N(O)+N(M) = C
ou C est une constante entière.
ex :
C = 3
Combo possibles  
I O M
3 0 0
0 3 0
0 0 3
2 1 0
2 0 1
1 2 0
0 2 1
0 1 2
1 0 2
1 1 1
 
soit 10 combinaisons
 
Je voudrais savoir combien de combinaison de set j'ai en fonction de C  et un chtit algo pr tous les générer tous.
Voila


Est-ce vraiment cela que tu veux ?
Tes N éléments sont-ils équivalents ?
Parce que là tu ne différencies pas les cas:
I={a},M={b,c},O={}
et
I={b},M={a,c},O={}

Reply

Marsh Posté le 24-05-2008 à 10:50:45    

oui, les éléments en eux mêmes n'ont pas d'importances, c'est les cardinaux de ensembles qui m'intéressent.

Reply

Marsh Posté le 24-05-2008 à 11:04:48    

gilou a écrit :

Plus concis certes, mais beaucoup moins optimal, puisque tu fais une double boucle qui fait C*C itérations.
A+,

tu as raison :

decoupe(X, I, J, K) :-
   between(0, X, I),
   X1 is X - I,
   between(0, X1, J),
   K is X1 - J.


 


Message édité par Trap D le 24-05-2008 à 11:07:07
Reply

Marsh Posté le 24-05-2008 à 12:51:05    

Nettement mieux, cette derniere ecriture :jap:  
Ca fait probablement (C+2)*(C+1)/2 tours de boucle.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-05-2008 à 13:04:26    

Ah, explique.
Pour le calcul avec 1000, j'ai 2,008,033 inferences avec la deuxième méthode alors que j'en ai 3,509,533 avec la première.

Reply

Marsh Posté le 24-05-2008 à 15:30:54    

Je parle des tours de boucle avec ta nouvelle écriture:
Il est clair que pour une valeur de I, on a C-I+1 valeurs de J (de 0 a C-I) et pour une valeur de I et une valeur de J données, on a une seule valeur de K.
Le nombre de tours de boucle total est donc Somme(I=0,I=C) de C-I+1
ce qui fait: (C+1)+ C + ... + 1, soit (C+1)*(C+2)/2
Pour 1000, ca devrait faire 501501 tours de boucle.
A+,


Message édité par gilou le 24-05-2008 à 15:32:51

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-05-2008 à 17:43:07    

D'accord, mais comme le premier programme était en (C+1)^2 avec des essais inutiles, j'ai quand même gagné de l'efficacité non ?

Reply

Marsh Posté le 24-05-2008 à 19:01:02    

Tout a fait, c'est ce que je disais dans mon post.
La, tu generes un triplet par iteration, sans iteration inutile.
Le code que je donne genere entre un et six triplets par iteration, sans iteration inutile. Donc plus efficace. Par contre il est totallement ciblé sur le problème précis, en utilisant la structure du groupe des permutations a trois elements et certaines de ses propriétés, et pas aisément generalisable au cas de n-uplets, contrairement au tien.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

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