IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Algorithmes et structures de données Discussion :

Somme des diviseurs propres


Sujet :

Algorithmes et structures de données

  1. #1
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut Somme des diviseurs propres
    Bonjour à tous,

    J'essaye de résoudre le problème situé à cette adresse (c'est un jeu de programmation / algorithmie) : http://www.spoj.pl/problems/DIVSUM/

    Il s'agit de faire la somme des diviseurs "propres" (proper divisors) sachant que le diviseur propre d'un nombre naturel est un diviseur strictement inférieur à ce nombre. Par exemple :

    20 a 5 diviseurs propres : 1, 2, 4, 5, 10, et la somme de ces diviseurs est : 1 + 2 + 4 + 5 + 10 = 22.

    Le problème c'est que j'obtiens constamment un "Time exceed" lors du jugement, ce qui indique que mon programme ne va pas assez vite...

    Je pense que mon algo est trop "naïf" mais je ne sais pas quoi faire pour aller plus vite...

    Comme l'indique le problème, le temps limite est de 3 seconde avec 200 000 nombres en entrée et avec chaque nombre n tel que (1 <= n <= 500000).

    Voilà, mon code :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int main()
    {
        int TestCases = 0, i = 0, x = 0;
        int num = 0, divisorSum = 0, bound = 0;
     
    	scanf("%d", &TestCases);
     
    	for (i = 0; i < TestCases; i++)
    	{
    	    scanf("%d", &num);
     
    	    divisorSum = 0;
     
            if (num % 2 == 0)
                bound = num / 2;
            else
                bound = num / 3;
     
            for (x = 1; x <= bound; x++)
            {
                if (num % x == 0)
                {
                    divisorSum += x;
                }
            }
            printf("%d\n", divisorSum);
    	}
     
    	return 0;
    }

    Que puis-je faire pour aller plus vite ?

    Je vous remercie

  2. #2
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    161
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 161
    Points : 185
    Points
    185
    Par défaut
    Tu peux essayer de faire une boucle de 2 à racine(n) puis dès que tu trouve un diviseur a, tu ajoute a puis n/a.

  3. #3
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    En fait, tester les diviseurs jusqu'à racine de n est une bonne idée.

    Ensuite, si tu veux aller plus vite, il va falloir ruser. En regardant les résultats des meilleurs, je vois que le premier à un temps d'éxécution assez petit ... 0. A mon avis, il y a eu un précalcul au moment de la compilation (méta-programmation c++).

    J'aurai bien testé le calcul en utilisant la décomposition en facteurs premiers :

    http://perso.orange.fr/yoda.guillaum...e.htm#theoreme

    La formule me parait sympa mais je ne sais pas si ça va être plus rapide.

  4. #4
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Points : 1 956
    Points
    1 956
    Par défaut
    Bonsoir,

    Merci pour vos réponses

    Effectivement, tester jusqu'à sqrt(n) était la solution !

    J'avais quand même "bad answer" après avoir soumis ma solution, mais j'étais sûr que c'était la bonne après avoir testé plusieurs cas...

    Après plusieurs longues minutes, je me suis aperçu qu'un cas spécial existait : la réponse à l'input "1" était forcément "0" (et non pas "1" comme mon algo me sortait..) !

    Ceci dit, le problème est résolu, merci beaucoup à vous deux pour votre aide

  5. #5
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    C'est l'algo classique pour déterminer les nombres dits "parfaits".
    En fait les diviseurs se trouvent DEUX par DEUX et non un par un, et il suffit de s'arrêter à la racine du nombre, puis de faire un dernier test pour savoir si on a affaire à un carré parfait.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
    #include <stdlib.h>
     
    int somme_div_propres (int n)
    { int i;
     int s;
      for (i=2, s=1; i*i<n; i++)
      //On ajoute deux par deux
      if (!(n%i)) s=s+i+n/i;
      // test du carré parfait
      if (n==i*i) n+=i; //si oui  on ajoute une seule fois
      return s;
    }
     
     
    int main()
    {
    	int test;
    	printf("Donner un nombre entier ");
    	scanf("%d", &test);
    	printf ("La somme de ses diviseurs propres est:%d\n",somme_div_propres(test));
    	return 0;
    }

  6. #6
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    711
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 711
    Points : 751
    Points
    751
    Par défaut
    dans le forum java ya eu une discussion dans le meme genre il n'y a as trop longtemps, j'avais donné un pseudo code naif mais pas trop :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    resultat <- []
     
    factorise(N, depart)
     
    //on traite le cas de 2 a part pour pouvoir ensuite avancer par pas de 2
    si depart == 2
      tant que 2 divise N
        resultat[] <- 2
        N=N/2
      fin tant que
      factorise(N,3) // on recurse
    sinon
      i<-depart
      tant que i ne divise pas N et i <= sqrt(N)+1// on cherche un diviseur
        i<-i+2
      fin tant que
      //si on en a trouvé un
      si i <= sqrt(N)+1
        tant que i divise N // on divise autant de fois que possible
          resultat[] <- i
          N=N/i
        fin tant que
        factorise(N, i+2) // on recurse
      sinon // c'est que N est premier, il n'y a plus de diviseurs
        resultat[] <- N // notre N est donc le dernier diviseur de notre nb de depart
      fin si
    fin fonction
    si tu veux un truc plus rapide mais pas trop technique nn plus, regarde l'algorithme de pollard de factorisation des entiers..

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    429
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 429
    Points : 475
    Points
    475
    Par défaut
    Bonjour,

    Je suspecte une faute de frappe dans le code de Zavonen ci-dessus.
    Le
    ne devrait-il pas être remplacé par
    ?

    Cordialement,

    Nicolas

  8. #8
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    @ Nicolas 75
    Bien sûr, il y a une erreur dans mon code corrigée par vous. Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ocaml Somme Des diviseurs d'un entier
    Par fethi510 dans le forum Caml
    Réponses: 3
    Dernier message: 01/06/2012, 14h42
  2. Somme des valeurs de certaines lignes
    Par Tartenpion dans le forum Langage SQL
    Réponses: 6
    Dernier message: 16/02/2006, 16h46
  3. somme des champs null
    Par s.rais dans le forum Access
    Réponses: 4
    Dernier message: 09/02/2006, 09h05
  4. Réponses: 2
    Dernier message: 09/01/2006, 16h10
  5. Somme des champs ? existe t il une fonction ...
    Par dark_vidor dans le forum Langage SQL
    Réponses: 6
    Dernier message: 02/01/2006, 11h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo