[Concours] Recherche de doublons dans une séquence

Recherche de doublons dans une séquence [Concours] - C++ - Programmation

Marsh Posté le 25-04-2004 à 23:50:13    

J'ai vu que certains aimaient bien les petits problèmes.
 
Alors voilà, je me lance donc en espérant que celui-là ne fera pas un bide complet. :D  
 
Le problème est simple : on a une séquence de 5 millions de chiffres aléatoires dans un tableau.
 
1er problème : (facile) trouver toutes les répétitions de n chiffres successifs dans le tableau. Les écrire dans un fichier txt, ainsi que leurs positions. On fera cette recherche pour toutes les séquences où : 7 <= n <= 15
 
2e problème : (moins facile) trouver la séquence de chiffres la plus longue qui est répétée au moins une fois.
 
Les meilleures solutions sont les plus rapides.
 
 
Ex. de sortie du premier programme :
 

Citation :


Séquences à 7 chiffres :
 
1542871 trouvé 8 fois [8520, 12555, 47520, 255356, 1352255, 1753256, 2751356, 4256752]  
0472123 trouvé 6 fois [154321, 788543, 853156, 1108256, 1332560, 1752212]  
etc
 
Séquences à 8 chiffres :
 
32845769 trouvé 11 fois [...]
 
etc
 
 
Total :  
1749 séquences à 7 chiffres
832 séquences à 8 chiffres
...
3 séquences à 15 chiffres
 
Durée : 74.245 s


 
 
NB : pour ceux que le challenge intéresse, il faut avoir tous la même séquence aléatoire. Je propose le générateur congruentiel suivant (Knuth) :
 
Graine : r = 17
itérations : r = (1664525 * r + 1013904223) modulo 2^32
 
Les 5 millions de chiffres de la séquences seront générés 5 par 5 en prenant les 5 premiers chiffres de r à chaque fois, donc seulement si r>9999.  
L'opération étant itérée un million de fois (partie non chronométrée).
 
Ouala, bonne cogitation !


Message édité par el muchacho le 26-04-2004 à 23:26:56
Reply

Marsh Posté le 25-04-2004 à 23:50:13   

Reply

Marsh Posté le 25-04-2004 à 23:57:10    

Donc, aucune restriction...
 
Le résultat du concours t'interresse-t-il ? (le code)


Message édité par christophe_d13 le 25-04-2004 à 23:58:07
Reply

Marsh Posté le 25-04-2004 à 23:59:02    

christophe_d13 a écrit :

Donc, aucune restriction...


 
Euh sur quoi ? Sur la mémoire ?
Disons que des solutions "raisonnables" devraient être envisagées, mais les algos intéressants sont tjrs acceptés.
 
Disons 100 Mo de RAM maxi.
 
edit : plutôt 128 Mo...


Message édité par el muchacho le 29-04-2004 à 22:58:42
Reply

Marsh Posté le 26-04-2004 à 00:00:54    

christophe_d13 a écrit :

Donc, aucune restriction...
 
Le résultat du concours t'interresse-t-il ? (le code)


 
Bien sûr, si ça vous intéresse d'essayer. Un petit concours d'optimisation est tjrs amusant (m^me si c'est du C, mais là, je risque de m'en prendre plein la tête... :heink: ).

Reply

Marsh Posté le 26-04-2004 à 00:01:27    

Y a pas que la mémoire... Le code également :
- code-morphing
- dynamic-code
- FPU ? MMX ? SSE ? SSE2 ? 3DNow ?
...


Message édité par christophe_d13 le 26-04-2004 à 00:01:59
Reply

Marsh Posté le 26-04-2004 à 00:02:43    

christophe_d13 a écrit :

Y a pas que la mémoire... Le code également :
- code-morphing
- dynamic-code
- FPU ? MMX ? SSE ? SSE2 ? 3DNow ?
...


 
Non, pas d'asm, juste du C/C++ ou autre langage portable.  
 
Edit : Sauf si ça intéresse certains, mais je crains que sur un forum C++...


Message édité par el muchacho le 26-04-2004 à 00:03:50
Reply

Marsh Posté le 26-04-2004 à 00:04:23    

Faut bien définir les rêgles...
- C/C++ pur sans les fonctions externes (sauf pour l'affichage) ?

Reply

Marsh Posté le 26-04-2004 à 00:06:33    

christophe_d13 a écrit :

Faut bien définir les rêgles...
- C/C++ pur sans les fonctions externes (sauf pour l'affichage) ?


 
Ok : C/C++ pur, on a le droit aux librairies standard, c'est tout.

Reply

Marsh Posté le 26-04-2004 à 20:30:01    

Ben ce problème n'a pas l'air de soulever l'enthousiasme... :ange:  

Reply

Marsh Posté le 29-04-2004 à 01:15:23    

Et zou, histoire que ce problème ne tombe pas tout de suite aux oubliettes. :bounce:  
 
Allez, à première vue, ça ressemble à du O(N^2), mais il y a clairement une solution simple en O(N*Log(N)), et même une en O(N) pour des petites séquences.

Reply

Marsh Posté le 29-04-2004 à 01:15:23   

Reply

Marsh Posté le 29-04-2004 à 01:19:24    

O(N) ? si tu tries que tu parcoures à la recherche de doublon, ça fait du N*Log(N) + N

Reply

Marsh Posté le 29-04-2004 à 01:25:16    

Squattage newbie : un cours simple sur les calculs de complexité vous auriez ?


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 29-04-2004 à 02:45:19    

Citation :

Les 5 millions de chiffres de la séquences seront générés 5 par 5 en prenant les 5 premiers chiffres de r à chaque fois, donc seulement si r>9999.  
L'opération étant itérée un million de fois (partie non chronométrée).


 
 
j'avais pas vu ça ... non mais ces quoi ces conneires ? tu te rends compte que c'est peut être la partie qui prends le plus de temps ? rien que cette fonction elle fait chier :o
 
à ce petit jeu là, t'as plus vite fait de distribuer le fichier avec la séquence :o

Reply

Marsh Posté le 29-04-2004 à 02:56:01    

ouais donne la liste, parce que là je commence à péter un plomb j'i bite rien à ta fonction de génération de merde, apprends à t'exprimer

Reply

Marsh Posté le 29-04-2004 à 03:00:50    

[:drapo] je relirais demain --> [:dodo]

Reply

Marsh Posté le 29-04-2004 à 03:12:08    

moi je laisse tomber, je me suis assez pris la tête sur des bêtises tout ça parce que l'énoncé est pas clair
 
« seront générés 5 par 5 »
alors la franchement je vois pas. à jamais

Reply

Marsh Posté le 29-04-2004 à 04:22:16    

Une petite question concernant la génération : tu peux préciser ou se trouve le LSB et le MSB pour 'r' et pour la 'séquence'. Histoire que tout le monde construise la séquence de la même facon.
 
Moi je trouve cette sequence :
 
10422197381276214297921856697316293946912835318827........


Message édité par xterminhate le 29-04-2004 à 04:31:08

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 29-04-2004 à 04:40:16    

el muchacho a écrit :


L'opération étant itérée un million de fois (partie non chronométrée).


 
Si je repete l'opération 1.000.000 de fois, j'obtiens les 2/3 des chiffres demandés. En fait certains résultats de r sont fortement réduits par le modulo (moins de 5 chiffres significatifs).
 
Compte-t-on alors les zéro en position MSB ? Je pense que non mais c'est pas super clair...


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 29-04-2004 à 05:14:43    

1542871 trouve 0 fois [  ].
0472123 trouve 3 fois [ 977257, 2767231, 3366731 ].
32845769 trouve 0 fois [  ].


 
Ma séquence est pas bonne ! :pt1cable: Elle est ennuyante ta formule à coder en C++ !


Message édité par xterminhate le 29-04-2004 à 20:38:03

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 29-04-2004 à 22:11:20    

ATTENTION !!! SOLUTION !!!
Ne lisez pas ce qu'il y a en-dessous si vous voulez chercher encore !
 

Taz a écrit :

O(N) ? si tu tries que tu parcoures à la recherche de doublon, ça fait du N*Log(N) + N


 
Oui, c'est ça ma solution en O(N log (N)) (le +O(N) n'a pas besoin d'être précisé, je crois). Mais en commençant à la coder, je me pose une question : le tri a besoin d'une fonction de comparaison, or je me demande si la comparaison des séquences ne va pas tout faire tomber par terre. J'ai bien l'impression que si.
Par ailleurs, ça bouffe quand même pas mal de mémoire : au moins n*N pour des séquences de taille n, plus un buffer en Log(N) supplémentaire pour le quicksort.
Mon autre solution (en fait celle d'un pote) est impraticable pour des séquences de plus de 8 ou 9 chiffres car elle prend 10^n en mémoire. Par contre, je doute qu'on puisse faire plus rapide : il suffit de faire un tableau de tous les nombres possibles avec n chiffres (donc 10^n chiffes), et d'y stocker les listes des index à chaque apparition. Super simple, super rapide mais super dispendieux en RAM.


Message édité par el muchacho le 30-04-2004 à 00:05:33
Reply

Marsh Posté le 29-04-2004 à 22:22:20    

Taz a écrit :

Citation :

Les 5 millions de chiffres de la séquences seront générés 5 par 5 en prenant les 5 premiers chiffres de r à chaque fois, donc seulement si r>9999.  
L'opération étant itérée un million de fois (partie non chronométrée).


 
 
j'avais pas vu ça ... non mais ces quoi ces conneires ? tu te rends compte que c'est peut être la partie qui prends le plus de temps ? rien que cette fonction elle fait chier :o
 
à ce petit jeu là, t'as plus vite fait de distribuer le fichier avec la séquence :o


 
Je sais. Le problème est de remplir le tableau avec des chiffres aléatoires.  
Et puis bon, si c'est ça qui t'empêche de dormir :
 

Code :
  1. #include <stdio.h>
  2. #include <vector>
  3. using namespace std;
  4. const int              N = 5000000;
  5. const unsigned long SEED = 17L;
  6. inline void alea(unsigned long &rand){
  7.   static unsigned long r;            // edit : bug : il faut initialiser r = SEED
  8.   rand = r = 1664525UL * r + 1013904223UL;
  9. }
  10. int remplit_v(vector<char> &v, const int n)
  11. {
  12.   unsigned long r = SEED;
  13.   char buf[5] = "";
  14.   vector<char> tmp;
  15.  
  16.   v.reserve(n);
  17.   for (int i = 0; i < n; i+= 5)
  18.     {
  19.       do alea(r); while (r < 10000L);
  20.       sprintf(buf, "%u:5", r);
  21.       tmp.assign(buf, &buf[sizeof(buf)]);  // faute de mieux
  22.       copy(tmp.begin(), tmp.end(), back_inserter(v));
  23.     }
  24.   return v.size();
  25. }


 
(ps : je sais, l'utilisation du sprintf n'est pas heureuse, mais c'est encore la fonction dont je me souviens le mieux. Enfin bon, on s'en fout, là n'est pas le plus important)


Message édité par el muchacho le 01-05-2004 à 07:51:23
Reply

Marsh Posté le 29-04-2004 à 22:39:59    

xterminhate a écrit :

Si je repete l'opération 1.000.000 de fois, j'obtiens les 2/3 des chiffres demandés. En fait certains résultats de r sont fortement réduits par le modulo (moins de 5 chiffres significatifs).
 
Compte-t-on alors les zéro en position MSB ? Je pense que non mais c'est pas super clair...


 
C'est pour cela que j'ai précisé "pour r > 9999" dans l'énoncé, donc pour les nombres à 5 chiffres minimum...
 
Mais je suis d'accord, cette partie de l'énoncé est la moins intéressante et la plus rebutante. Le plus simple est que tout le monde parte sur le code que je donne (j'espère qu'il n'y a pas de bug).
 
Pour info, il me donne (N=5000000): (!! FAUX !!)
40 premiers : 1013911964351982868416495267061476227489
40 derniers : 3125048398216972947012249492535033240745


Message édité par el muchacho le 01-05-2004 à 07:49:59
Reply

Marsh Posté le 29-04-2004 à 23:02:36    

xterminhate a écrit :

1542871 trouve 0 fois [  ].
0472123 trouve 3 fois [ 977257, 2767231, 3366731 ].
32845769 trouve 0 fois [  ].


 
Ma séquence est pas bonne ! :pt1cable: Elle est ennuyante ta formule à coder en C++ !


 
Ben oui, c'est bien pour ça que je la proposais.  :sol:  
 
C'est un bon exercice d'utilisation des conteneurs STL (c'est aussi un bon exercice pour les codeurs en C). Si je suis pas trop paresseux, je m'en ferai peut-être une version des algos en Ocaml aussi (à moins que ça intéresse Joelf ou nraynaud). Une petite comparaison des perfs pourrait être intéressante (je n'ai aucune idée de ce que ça peut donner).
 
Ce problème n'est pas complètement gratuit, il a je pense des connexions (lointaines) avec le problème de séquençage de l'ADN, ou avec l'indexation de grands textes.

Reply

Marsh Posté le 30-04-2004 à 01:07:17    

sprintf(buf, "%u:5", r);  
 
skoi ça ?

Reply

Marsh Posté le 30-04-2004 à 01:10:26    

char buf[5] = "\0";  
 
en plus t'es un malin toi
 
 
pas standard
#include <stdio.h>
 
 
 
  const int              N = 5000000;
  const unsigned long SEED = 17L;
   
  void alea(unsigned long &rand){
      static unsigned long r;
      rand = r = 1664525L * r + 1013904223L;
  }  
 
à mettre dans namespace, à inliner
 
 
 
vector<char> &v
 
la je comprends pas le prototype, on parle pas d'entier ?

Reply

Marsh Posté le 30-04-2004 à 07:11:19    

:wahoo: Bon c'est n'importe quoi la :)
 
J'ai un code similaire et mon premier nombre est 1042201148. Alors je vois pas comment tu extrais 10139 de ce premier nombre. J'ai vérifié à la main mes premiers nombres ....
 
Pour info, voila mon code de génération :
 

Code :
  1. std::string generation()
  2. {
  3. std::string alea;
  4. std::string::size_type taille_sequence( alea.size() );
  5. const unsigned long multiplier( 1664525UL );
  6. const unsigned long addend( 1013904223UL );
  7. unsigned long valeur( 17UL );
  8. while( taille_sequence < 1000000 )
  9. {                       
  10. if( ( valeur =  ( multiplier * valeur + addend ) ) > 9999UL )
  11. {
  12. std::ostringstream str;
  13. str << valeur;
  14. alea += str.str().substr(0,5);
  15. taille_sequence++;
  16. }
  17. }
  18. return alea;
  19. }


 
Ce qui m'etonne, c'est qu'en C++ la valeur de ton masque ne passe pas. Donc, tu n'appliques pas vraiment la bonne formule (ce qui est mon cas aussi bien sur) donnée dans l'ennoncé ! Je me trompe ?
 
En fait, on calcule ca :
 

newseed = ( seed * multiplier ) % 2^32 + ( adder ) % 2^32


 
En C, on aurait accès au __int64 mais pas en C++, d'ou ma remarque precedente. [:airforceone]


Message édité par xterminhate le 30-04-2004 à 23:42:50

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 30-04-2004 à 07:22:36    

tu trouve pas ca un peu lourd de specifier a chaque fois std::, tu fais jamais de using... ? surtout que la tu utilise un seul namespace

Reply

Marsh Posté le 30-04-2004 à 07:29:25    

Oui, je sais... ca rend le code un peu moins lisible, désolé.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 30-04-2004 à 07:57:19    

Taz a écrit :

char buf[5] = "\0";  
 
en plus t'es un malin toi
 
 
pas standard
#include <stdio.h>
 
 
 
  const int              N = 5000000;
  const unsigned long SEED = 17L;
   
  void alea(unsigned long &rand){
      static unsigned long r;
      rand = r = 1664525L * r + 1013904223L;
  }  
 
à mettre dans namespace, à inliner
 
 
 
vector<char> &v
 
la je comprends pas le prototype, on parle pas d'entier ?


 
Ah, je sens qu'on est sur les rails, là. :)  
Dans le reste de mon code, j'inline, mais tu as raison.
Pour le printf, si tu peux me rappeler la version strstream, je changerai volontiers ma petite fonction de génération pour la rendre plus C++.
 
edit : pas la peine, xterminhate me la donne...
 
En fait, mon problème s'applique plutôt à un tableau de caractères (mais il peut se généraliser à toute collection d'objets finie ordonnée). Le fait que je dise que ces caractères soient des chiffres, c'est que je l'ai imaginé comme ça. Donc pour ce problème, ce sont des chiffres. Tu peux utiliser un vector<int> si tu préfères, tant que tu obtiens les mêmes valeurs dans ton tableau.

Reply

Marsh Posté le 30-04-2004 à 08:00:07    

xterminhate a écrit :

:wahoo: Bon c'est n'importe quoi la :)
 
J'ai un code similaire et mon premier nombre est 1042201148. Alors je vois pas comment tu extrais 10139 de ce premier nombre. J'ai vérifié à la main mes premiers nombres ....
 
Pour info, voila mon code de génération :
 

Code :
  1. std::string generation()
  2. {
  3. std::string alea;
  4. std::string::size_type taille_sequence( alea.size() );
  5. const unsigned long multiplier( 1664525UL );
  6. const unsigned long addend( 1013904223UL );
  7. // const unsigned long mask( 4294967295UL );
  8. unsigned long valeur( 17UL );
  9. while( taille_sequence < 1000000 )
  10. {                       
  11. if( ( valeur =  ( multiplier * valeur + addend ) ) > 9999UL )
  12. {
  13. std::ostringstream str;
  14. str << valeur;
  15. alea += str.str().substr(0,5);
  16. taille_sequence++;
  17. }
  18. }
  19. return alea;
  20. }


 
Ce qui m'etonne, c'est qu'en C++ la valeur de ton masque ne passe pas. Donc, tu n'appliques pas vraiment la bonne formule (ce qui est mon cas aussi bien sur) donnée dans l'ennoncé ! Je me trompe ?
 
En fait, on calcule ca :
 

newseed = ( seed * multiplier ) % 2^32 + ( adder ) % 2^32


 
En C, on aurait accès au __int64 mais pas en C++, d'ou ma remarque precedente. [:airforceone]


 
Effectivement, tu as corrigé toi-même. J'ai vu le pb quand j'ai compilé. Le plus simple (ce que j'ai fait dans ma fonction), c'est de virer carrément la partie modulo.

Reply

Marsh Posté le 30-04-2004 à 08:03:56    

cai juste qu'il me semble pas que cette syntax de format de printf soit standard.
 
char buf[5] = "\0"; t'as réalisé ce que tu as écris là ?

Reply

Marsh Posté le 30-04-2004 à 08:11:53    

Taz a écrit :

cai juste qu'il me semble pas que cette syntax de format de printf soit standard.
 
char buf[5] = "\0"; t'as réalisé ce que tu as écris là ?


 
Quel est le pb ?
(bon cassos boulot)


Message édité par el muchacho le 30-04-2004 à 08:14:22
Reply

Marsh Posté le 30-04-2004 à 08:30:30    

el muchacho a écrit :

Quel est le pb ?
(bon cassos boulot)


 
char buf[5] ;
buf[4] = '\0' ;
 
?

Reply

Marsh Posté le 30-04-2004 à 08:41:55    

Citation :

char buf[5] ;  
buf[4] = '\0' ;


 
ca sert a koi ?  :D  
 

Reply

Marsh Posté le 30-04-2004 à 09:12:05    

skelter a écrit :

Citation :

char buf[5] ;  
buf[4] = '\0' ;


 
ca sert a koi ?  :D


à rien ! j'espère de comprendre ce qu'il a voulu faire..

Reply

Marsh Posté le 30-04-2004 à 09:55:02    

"" fais exactement ce qu'il faut.

Reply

Marsh Posté le 30-04-2004 à 20:53:24    

Bon, revennons à nos moutons !... le concours :p
 
El much -> tu as vérifié ton code parce que pour le moment, on a vraiment pas la meme sequence de départ !


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 30-04-2004 à 21:00:09    

el muchacho : distribue un fichier avec la séquence, chaque élément séparé par un espace, le tout compréssé (et pas en zip/rar hein)

Reply

Marsh Posté le 30-04-2004 à 22:20:20    

JagStang a écrit :

char buf[5] ;
buf[4] = '\0' ;
 
?


 
Ouais, la grosse honte... :D  
J'ai vu la bourde quand j'y ai pensé dans le bus.  
En fait, je pensais plutôt à une initialisation du genre :
 
char buf[5] = "";
 
De toute façon, ça n'a pas d'incidence ici.


Message édité par el muchacho le 30-04-2004 à 22:21:18
Reply

Marsh Posté le 30-04-2004 à 22:40:12    

xterminhate a écrit :

Bon, revennons à nos moutons !... le concours :p
 
El much -> tu as vérifié ton code parce que pour le moment, on a vraiment pas la meme sequence de départ !


 
Bon je revois mon code...


Message édité par el muchacho le 30-04-2004 à 22:49:41
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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