web-dev-qa-db-fra.com

Obtenir efficacement tous les diviseurs d'un nombre donné

Selon ce post , nous pouvons obtenir tous les diviseurs d’un nombre grâce aux codes suivants.

for (int i = 1; i <= num; ++i){
    if (num % i == 0)
        cout << i << endl;
}

Par exemple, les diviseurs du nombre 24 sont 1 2 3 4 6 8 12 24.

Après avoir cherché quelques articles connexes, je n’ai trouvé aucune bonne solution. Existe-t-il un moyen efficace d'y parvenir?

Ma solution:

  1. Trouvez tous les facteurs premiers du nombre donné grâce à cette solution .
  2. Obtenez toutes les combinaisons possibles de ces facteurs premiers.

Cependant, cela ne semble pas être bon.

47
zangw

Les facteurs sont appariés. 1 et 24, 2 et 12, 3 et 8, 4 et 6

Une amélioration de votre algorithme pourrait consister à itérer à la racine carrée de num au lieu de tout le chemin à num, puis à calculer les facteurs liés en utilisant num / i.

73
Yu Hao

Vous devriez vraiment vérifier jusqu'à la racine carrée de num comme sqrt (num) * sqrt (num) = num:

Quelque chose sur ces lignes:

int square_root = (int) sqrt(num) + 1;
for (int i = 1; i < square_root; i++) { 
    if (num % i == 0&&i*i!=num)
        cout << i << num/i << endl;
    if (num % i == 0&&i*i==num)
        cout << i << '\n';
}
27
SMA

Il n’existe pas de moyen efficace au sens de la complexité algorithmique (un algorithme à complexité polynomiale) connu de la science. Donc, itérer jusqu'à ce que la racine carrée, comme déjà suggéré, soit aussi bon que possible.

C'est principalement pour cette raison qu'une grande partie de la cryptographie actuellement utilisée est basée sur l'hypothèse qu'il est très fastidieux de calculer une factorisation première d'un entier donné.

13
SpaceTrucker

Voici mon code: 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

#define pii pair<int, int>

#define MAX 46656
#define LMT 216
#define LEN 4830
#define RNG 100032

unsigned base[MAX / 64], segment[RNG / 64], primes[LEN];

#define sq(x) ((x)*(x))
#define mset(x,v) memset(x,v,sizeof(x))
#define chkC(x,n) (x[n>>6]&(1<<((n>>1)&31)))
#define setC(x,n) (x[n>>6]|=(1<<((n>>1)&31)))

// http://zobayer.blogspot.com/2009/09/segmented-sieve.html
void sieve()
{
    unsigned i, j, k;
    for (i = 3; i<LMT; i += 2)
        if (!chkC(base, i))
            for (j = i*i, k = i << 1; j<MAX; j += k)
                setC(base, j);
    primes[0] = 2;
    for (i = 3, j = 1; i<MAX; i += 2)
        if (!chkC(base, i))
            primes[j++] = i;
}


//http://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
vector <pii> factors;
void primeFactors(int num)
{
    int expo = 0;   
    for (int i = 0; primes[i] <= sqrt(num); i++)
    {
        expo = 0;
        int prime = primes[i];
        while (num % prime == 0){
            expo++;
            num = num / prime;
        }
        if (expo>0)
            factors.Push_back(make_pair(prime, expo));
    }

    if ( num >= 2)
        factors.Push_back(make_pair(num, 1));

}

vector <int> divisors;
void setDivisors(int n, int i) {
    int j, x, k;
    for (j = i; j<factors.size(); j++) {
        x = factors[j].first * n;
        for (k = 0; k<factors[j].second; k++) {
            divisors.Push_back(x);
            setDivisors(x, j + 1);
            x *= factors[j].first;
        }
    }
}

int main() {

    sieve();
    int n, x, i; 
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> x;
        primeFactors(x);
        setDivisors(1, 0);
        divisors.Push_back(1);
        sort(divisors.begin(), divisors.end());
        cout << divisors.size() << "\n";
        for (int j = 0; j < divisors.size(); j++) {
            cout << divisors[j] << " "; 
        }
        cout << "\n";
        divisors.clear();
        factors.clear();
    }
}

La première partie, sieve (), est utilisée pour trouver les nombres premiers et les placer dans le tableau de nombres premiers []. Suivez le lien pour en savoir plus sur ce code (tamis au niveau du bit).

La seconde partie, primeFactors (x) prend un entier (x) en entrée et en découvre les facteurs premiers et l'exposant correspondant, puis les met dans des facteurs vectoriels []. Par exemple, primeFactors (12) va peupler les facteurs [] de la manière suivante: 

factors[0].first=2, factors[0].second=2
factors[1].first=3, factors[1].second=1

comme 12 = 2 ^ 2 * 3 ^ 1

La troisième partie, setDivisors (), s’appelle récursivement pour calculer tous les diviseurs de x, en utilisant le vecteur facteurs [] et les met dans des diviseurs vectoriels [].

Il peut calculer les diviseurs de n'importe quel nombre qui convient à int. Aussi c'est assez rapide.

7
Rocky Johnson

Il existe de nombreuses bonnes solutions pour trouver tous les facteurs premiers de nombres pas trop grands. Je voulais juste souligner qu’une fois que vous les avez, aucun calcul n’est requis pour obtenir tous les facteurs.

si N = p_1^{a}*p_{2}^{b}*p_{3}^{c}.....

Ensuite, le nombre de facteurs est clairement (a+1)(b+1)(c+1).... puisque chaque facteur peut être zéro jusqu’à un moment.

par exemple. 12 = 2^2*3^1 donc il a 3*2 = 6 facteurs. 1,2,3,4,6,12

======

Au départ, je pensais que vous vouliez simplement connaître le nombre de facteurs distincts. Mais la même logique s'applique. Vous venez de parcourir l'ensemble des nombres correspondant aux combinaisons possibles d'exposants.

donc dans l'exemple ci-dessus:

00
01
10
11
20
21

vous donne les facteurs 6.

5
phil_20686
int result_num;
bool flag;

cout << "Number          Divisors\n";

for (int number = 1; number <= 35; number++)
{
    flag = false;
    cout << setw(3) << number << setw(14);

    for (int i = 1; i <= number; i++) 
    {
        result_num = number % i;

        if (result_num == 0 && flag == true)
        {
            cout << "," << i;
        }

        if (result_num == 0 && flag == false)
        {
            cout << i;
        }

        flag = true;
    }

    cout << endl;   
}
cout << "Press enter to continue.....";
cin.ignore();
return 0;
}
0
ying
for (int i = 1; i*i <= num; ++i)
{
    if (num % i == 0)
    cout << i << endl;
    if (num/i!=i)
    cout << num/i << endl;
}
0
//Try this,it can find divisors of verrrrrrrrrry big numbers (pretty efficiently :-))
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<conio.h>

using namespace std;

vector<double> D;

void divs(double N);
double mod(double &n1, double &n2);
void Push(double N);
void show();

int main()
{
    double N; 
    cout << "\n Enter number: "; cin >> N;

    divs(N); // find and Push divisors to D

    cout << "\n Divisors of "<<N<<": "; show(); // show contents of D (all divisors of N)

_getch(); // used visual studio, if it isn't supported replace it by "getch();"
return(0);
}

void divs(double N)
{
    for (double i = 1; i <= sqrt(N); ++i)
    {
        if (!mod(N, i)) { Push(i); if(i*i!=N) Push(N / i); }
    }
}

double mod(double &n1, double &n2)
{
    return(((n1/n2)-floor(n1/n2))*n2);
}

void Push(double N)
{
    double s = 1, e = D.size(), m = floor((s + e) / 2);
    while (s <= e)
    {   
        if (N==D[m-1]) { return; }
        else if (N > D[m-1]) { s = m + 1; }
        else { e = m - 1; }
        m = floor((s + e) / 2);
    }
    D.insert(D.begin() + m, N);
}

void show()
{
    for (double i = 0; i < D.size(); ++i) cout << D[i] << " ";
}
0
Ragib

Voici l'implémentation Java de this approche:

public static int countAllFactors(int num)
{
    TreeSet<Integer> tree_set = new TreeSet<Integer>();
    for (int i = 1; i * i <= num; i+=1)
    {
        if (num % i == 0)
        {
            tree_set.add(i);
            tree_set.add(num / i);
        }
    }
    System.out.print(tree_set);
    return tree_set.size();
}
0
Pratik Patil