Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Получить все простые делители числа

16K
10 августа 2007 года
Draconit
39 / / 10.08.2007
Задача: Дано натуральное число n. Получить все простые делители этого числа.

Объясните пожалуйста как решить эту задачу, т.е. алгоритм действий, т.к. я не очень понимаю как и в каком порядке нужно решать.

Язык программирования не важен, мне главное алгоритм, желательно словами, т.к. я пока только разбираюсь в 2-ух языках: Паскаль и Си.
257
10 августа 2007 года
kosfiz
1.6K / / 18.09.2005
да все вроде просто. организуешь цикл от 1 до n и проверяешь в цикле, если остаток от деления n на i равен 0, где i = 2..n, значит i - делитель числа n, и потом тут же проверяешь i на то простое ли это число или нет, а простым называется число, которое делится только на 1 и на себя, т.е. тебе надо будет организовать цикл от 2 до i-1 и считать сколько делителей у i, если не одного то простое число и оно то что нам нужно.
63
10 августа 2007 года
Zorkus
2.6K / / 04.11.2006
Цитата: Draconit
Задача: Дано натуральное число n. Получить все простые делители этого числа.

Объясните пожалуйста как решить эту задачу, т.е. алгоритм действий, т.к. я не очень понимаю как и в каком порядке нужно решать.

Язык программирования не важен, мне главное алгоритм, желательно словами, т.к. я пока только разбираюсь в 2-ух языках: Паскаль и Си.


1. Найти все простые числа до половины данного числа, для каждого их них проверить делитель или нет.
2. Найти все делители, выбрать из них простые числа.

2.0K
10 августа 2007 года
WidowMaker
212 / / 05.04.2005
Можно оптимизировать поиск если находить простые числа || с нахождением делителей. Например начинаем с набором простых чисел: 2, 3, 5, 7...
 
Код:
1. Индекс простого числа=0:
2. получить следующее простое число,
    если его нет, то находим новое простое число и добавляем  в набор;
3. делим число на простое число
    если делится, то делим наше число и к п1,
    если не делится, то
        если остаток ==1 - подсчет окончен,
        в противном случае к п2
28K
10 августа 2007 года
Vladimir.
12 / / 03.08.2007
Спасибо to cheburator за замечания касательно "читабильности" кода, посторался исправить.
Код:
#include<iostream.h>

/**********************************************************
cancellation() Выясняет являеться ли divisor делителем для
number, если да, то находит кратность делителя и возвращает
зачение (number/(divisor^S))
**********************************************************************/

int cancellation(int divisor,int number);

/************************************************************************
Ведём перебор возможных делителей для number (он будет
лежать в промежутке до корня из number включительно, если
number - сложное, см.http://forum.codenet.ru/
showthread.php?t=40875&page=2 сообщение №18), возможное
значение передаем функции cancellation(); перебор возможных
делителей оптимизирован исключением чисел вида 2k, где
k=1,2,3,4,5,6,...; по предложению cheburator'а возможно
исключение чисел вида 3k, 5k  и т.п.
*********************************************************************/

int main()
{
 int n,number;
 cout<<"\nInput number..."<<endl;
 cin>>n;
 cout<<"\nSolve..."<<endl;

 number=n;
 number=cancellation(2,number);

 int k=3;
 while (k*k <= number)
 {
   psi=cancellation(k,psi);
   k+=2;
 }

  cout<<number;
  cout<<"\nDone..."<<endl;

  return (0);
}

int cancellation (int divisor,int number)
{
 if ((number%divisor)==0) cout<<divisor<<"\t";
 while((number%divisor)==0) number/=divisor;
 return (number);
}
16K
11 августа 2007 года
Draconit
39 / / 10.08.2007
Ну вот вроде решил:
Код:
#include <stdio.h>;
#include <math.h>;
#include <stdlib.h>;
#include <conio.h>;
int n,i,a,b;
void main()
{
clrscr();
puts("Введите n");
scanf("%i",&n);
printf("Простые делители числа %i:\n",n);
for (i=2;i<=(n/2);i++)
 {
  if ((n%i)==0)
   {
    b=0;
    for (a=2;a<=(i-1);a++)
     {
      if ((i%a)==0) b++;
     }
    if (b==0) printf("%i\n",i);
   }
 }
getch();
}


Вроде же правильно?:)
257
11 августа 2007 года
kosfiz
1.6K / / 18.09.2005
Draconit, а ты n=3 ввести пробывал? должно выдать как раз что простой делитель 3, а у тебя нет.
257
11 августа 2007 года
kosfiz
1.6K / / 18.09.2005
[quote=Zorkus]1. Найти все простые числа до половины данного числа, для каждого их них проверить делитель или нет.
2. Найти все делители, выбрать из них простые числа.[/quote]
я так понимаю это два метода решения поставленной задачи, правильно? вот против второго ничего не имею против, но насчет первого есть вопрос:
берем n=3 потом, половина данного числа 1.5, простых чисел являющихся делителями n нет в интервале от 1 до 1.5(ну или если округлить, то 2), тогда как же быть? ведь мы теряем 3.
2.0K
11 августа 2007 года
WidowMaker
212 / / 05.04.2005
Ну пошевили серым веществом, какое число дает 0 простых делителей?

ЗЫ: правда Draconit не считает их колво...
257
11 августа 2007 года
kosfiz
1.6K / / 18.09.2005
Цитата: WidowMaker
Ну пошевили серым веществом, какое число дает 0 простых делителей?

ЗЫ: правда Draconit не считает их колво...


ты это вообще к чему?;)

2.0K
11 августа 2007 года
WidowMaker
212 / / 05.04.2005
Цитата: Draconit
Ну вот вроде решил:
Код:
#include <stdio.h>;
#include <math.h>;
#include <stdlib.h>;
#include <conio.h>;
int n,i,a,b;
void main()
{
clrscr();
puts("Введите n");
scanf("%i",&n);
printf("Простые делители числа %i:\n",n);
[color=green]/*[предварительно >>до первой единицы]*/[/color]
[color=green]/*for(i=3;i<n;i++)*/[/color]
for (i=2;i<=(n/2);i++)
 {
  if ((n%i)==0)
   {
    b=0;
      [color=green]/*if( !(i & 1) ) continue;*/[/color]
      [color=green]/*for(a=3;a<=i/2;a+=2)*/[/color]
 [highlight]   for (a=2;a<=(i-1);a++)[/highlight]
      if (i%a==0)
      {
            b++;
            break;
      }
      if(!b) printf("%i\n",i);
   }
 }
getch();
}


Ты слишком часто проверяешь четные числа на простоту...

2.0K
11 августа 2007 года
WidowMaker
212 / / 05.04.2005
Цитата: kosfiz
берем n=3 потом, половина данного числа 1.5, простых чисел являющихся делителями n нет в ...., тогда как же быть?



[QUOTE=WidowMaker ]
Ну пошевили серым веществом, какое число дает 0 простых делителей?
ЗЫ: правда Draconit не считает их колво...
[/QUOTE]

Что к чему?

257
11 августа 2007 года
kosfiz
1.6K / / 18.09.2005
ну и объясни какое отношение имеет твой вопрос к моему сообщению
2.0K
11 августа 2007 года
WidowMaker
212 / / 05.04.2005
1. Ты писал что Draconit пропускает число 3 (в общем случае любое если n простое число);
2. Ты писал Zorkus'у, что выполняя поиск до n/2 мы теряем простое n.

Я указал на то что достаточно ввести счетчик обнаруженных делителей числа, и если он в конце расчетов ==0, то число n - простой делитель самого себя....;)
257
11 августа 2007 года
kosfiz
1.6K / / 18.09.2005
Цитата: WidowMaker
1. Ты писал что Draconit пропускает число 3 (в общем случае любое если n простое число);
2. Ты писал Zorkus'у, что выполняя поиск до n/2 мы теряем простое n.

Я указал на то что достаточно ввести счетчик обнаруженных делителей числа, и если он в конце расчетов ==0, то число n - простой делитель самого себя....;)


:D
мда...
отвечу тебе по пунктам.
1. я знаю и вижу и думаю остальные это видят и знают, а что это разве непонятно? человеку надо вообще-то указать хотя бы пример, чтобы он задумался. а теперь смотри если n=3, то пропускается число 3, которое что? правильно, которое обозначено как n, а значит пропускается n! так что [quote=WidowMaker]пошевили серым веществом[/quote];)
2. это я писал Zorkus'у и ждал ответа от него. мы теряем n по тому подходу, который он предложил и он про счетчик ничего не писал, так что подход неправильный. не следует лезть в разговор, тем более когда видно, что я обращаюсь к определенному собеседнику.

2.0K
11 августа 2007 года
WidowMaker
212 / / 05.04.2005
Извини... ответ писался на первое замечание
Если посмотришь на мой следующий мсж то я обратился к Draconit с предложением улучшить перебор.
Насчет
Цитата:
...а значит пропускается n! так что...


я не совсем тебя понял
ЗЫ: на счет серого вещества (читай подумай), не обижайся, эт я от скуки начинаю хамить;)

320
11 августа 2007 года
m_Valery
1.0K / / 08.01.2007
Цитата: WidowMaker

ЗЫ: на счет серого вещества (читай подумай), не обижайся, эт я от скуки начинаю хамить;)


[COLOR="Red"]Что ? От скуки ? Так вот : хамить ты здесь не будешь :mad: ни от скуки , ни от других своих недугов.Поверь мне.Следующее нарушение будет для тебя последним.[/COLOR]

28K
11 августа 2007 года
Vladimir.
12 / / 03.08.2007
Прошу прощения за стиль изложения.(не знаю как на форуме формулы прописывать, если кто умеет киньте, пожалуйста, ссылку в ЛС)
Вижу перебор простых чисел идет до n/2,
немного рассуждений:
Пусть P_1,P_2, P_3, P_4,..,P_k-1, P_k - простые числа, причем P_i<P_i+1 при любых

i=1,2,3,....k-1.
любое число можно представить ввиде
n = {(P_1)^S_1}*{(P_2)^S_2}*{(P_3)^S_3}*{(p_4)^S_4}*...*{(P_k-1)^S_k-1}*{(P_k)^S_k} //^

-возведение в степень 2^3=8;
где S_i = 0,1,2,3... кратность простого множителя.
оценим максимальный множитель:
так как P_i<P_i+1 оценим для P_k.
{(P_k)^S_k} = n/[{(P_1)^S_1}*{(P_2)^S_2}*{(P_3)^S_3}*...*{(P_k-1)^S_k-1}]

пусть сложилась ситуация, такая что

[{(P_1)^S_1}*{(P_2)^S_2}*{(P_3)^S_3}*{(p_4)^S_4}*...*{(P_k-1)^S_k-1}] = 1
то есть S_i = 0 для i = 1,2,3,4,.., k-2,k-1;

тогда {(P_k)^S_k} = n (а обычно меньше т.к. знаменатель обычно не равен 1), т.е.
{(P_k)^S_k} <= n

вариант 1: S_k = 0, невозможен при правильном k (доказывать не будем, впринципе очевидно.)
вариант 2: S_k = 1, n = P_k; n простое.
вариант 3: S_k = 2, p_k*p_k <= n т.е. p_k<= (n^0.5)
вариант 4: S_k = 3, p_k*p_k*p_k<=n p_k< (n^0.5)

таким образом проверять простые делители следует от 2 до значения квадратного корня из n включительно, а так же убедиться в том что n не являеться простым. (Последнее верно если нашелся хотя бы один делитель для n в указанном промежутке, если же нет, то n простое.)

--------------------------------------------------------------------------------------
редактирование:
Цитата:
Разве? Вот к примеру число 15, у него 2 простых делителя 3 и 5, но если мы будем искать до значения квадратного корня (а он равен 3,873), то мы упускаем из виду 5. Или я что-то неправильно понял?


нет, это я неправильно написал. должно быть:

Цитата:
таким образом проверять простые делители следует от 2 до значения квадратного корня из n включительно,и для сложного числа n в указанном промежутке обязательно найдеться простой делитель;


например, 657: корень(657)<25, делителители в промежутке от 2 до 25 : 3, кратность равна двум.
657/(3*3) =73;
корень(73)<9, делителей в промежутке от 2 до 9 нет, следовательно 73 - простое;
ответ: разложение 657 = 3*3*73, делители 3 и 73

16K
12 августа 2007 года
Draconit
39 / / 10.08.2007
Цитата: Vladimir.
таким образом проверять простые делители следует от 2 до значения квадратного корня из n включительно, а так же убедиться в том что n не являеться простым. (Последнее верно если нашелся хотя бы один делитель для n в указанном промежутке, если же нет, то n простое.)



Разве? Вот к примеру число 15, у него 2 простых делителя 3 и 5, но если мы будем искать до значения квадратного корня (а он равен 3,873), то мы упускаем из виду 5. Или я что-то неправильно понял?

А задачку кажется сделал:

Код:
#include <stdio.h>;
#include <math.h>;
#include <stdlib.h>;
#include <conio.h>;
int n,i,a,b,c;
void main()
{
clrscr();
c=0;
puts("Vvedite n");
scanf("%i",&n);
printf("Prostue deliteli chisla %i:\n",n);
for (i=2;i<=n;i++)
 {
  if ((n%i)==0)
   {
    b=0;
    for (a=2;a<=(i-1);a++)
     {
      if ((i%a)==0) b++;
     }
    if (b==0)
     {
      printf("%i\n",i);
     }
   }
  else c++;
 }
if (c=0) printf("%i\n",n);
//printf("%i",c);
getch();
}


Вроде на этот раз нормально?
257
12 августа 2007 года
kosfiz
1.6K / / 18.09.2005
вопрос к автору: а зачем все строки с переменной c?
и еще
 
Код:
if (c=0) printf("%i\n",n);

я так понимаю ты сравниваешь, так тогда тебе надо == использовать.
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
Предлагаю построить простые, не превосходящие N, при помощи решета Эратосфена, и в ходе построения проверять делимость N на очередное простое.
Алгоритм решета Эратосфена приведен здесь:
http://forum.codenet.ru/showpost.php?p=198722&postcount=5
Этот алгоритм, правда, можно улучшить за счет того, что:
1. При вычеркивании чисел достаточно вычеркивать до корня из N (имеется в виду, для простых, не превосходящих корня из N, но вычеркиваются числа до N).
2. Приступая к вычеркиванию кратных очередного простого числа p, вычеркивание следует начинать с p^2.
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
Собственно, вот и код:
Код:
#include <deque>
#include <iostream>
#include <math.h>

using namespace std;

// Алгоритм: ищем простые числа, не превосходящие корня из N. Начинаем с числа 2.
// Для каждого найденного простого проверяем делимость N на него.
// "Вычеркиваем" числа, кратные текущему простому p (вычеркивание начинаем с p^2 и идем до N).
// Ищем следующее невычеркнутое число - это будет следующее простое число.
// И т. д. в цикле, пока не превзошли корня из N.
// Часть из оставшиеся чисел после корня из N могут также быть простыми.
// Таким образом, нужно искать невычеркнутые числа после корня из N и для них также проверять делимость N.

// Ограничимся ста миллионами
#define MAX_VAL 100000000

void main (void)
{
    int max_val;
    cout << "Enter number: ";
    cin >> max_val;
    if (max_val > MAX_VAL || max_val < 2)
    {
        cout << "Wrong limits";
        return;
    };
    // Поиск простых ведем до корня из max_val
    int sqrt_max_val = (int)sqrt((double)max_val);
    // Признаки "вычеркнутости" чисел (элементы 0 и 1 не используются)
    deque<bool> flags (max_val+1, false);  // Массив признаков вычеркнутости чисел.
        // flags означает, вычеркнуто ли i или нет (true - вычеркнуто, false - нет).
        // Первоначально все числа не перечеркнуты
    int current_value = 2;    // Текущее простое число
    do
    {
        // Проверим делимость на текущее простое число
        if (max_val % current_value == 0)
            cout << current_value << endl;
        // Вычеркиваем все числа, кратные current_value, начиная с его квадрата
        for (int i = current_value * current_value; i <= max_val; i += current_value)
            flags = true;
        // Ищем следующее невычеркнутое число
        for (++current_value; current_value <= sqrt_max_val && flags[current_value]; ++current_value) ;
    } while (current_value <= sqrt_max_val);
    // Проверим все невычеркнутые числа больше корня из N
    for (current_value = sqrt_max_val+1; current_value <= max_val; ++current_value)
        if (!flags[current_value] && max_val % current_value == 0)
            cout << current_value << endl;
};
350
12 августа 2007 года
cheburator
589 / / 01.06.2006
Небольшое усовершенствование:
Код:
#include <deque>
#include <iostream>
#include <math.h>
#include <windows.h>

using namespace std;

// Алгоритм.
// 1 Этап. Ищем простые числа, не превосходящие корня из N. Начинаем с числа 2.
// Для каждого найденного простого проверяем делимость N на него.
// "Вычеркиваем" числа, кратные текущему простому p (вычеркивание начинаем с p^2 и идем до N).
// Ищем следующее невычеркнутое число - это будет следующее простое число.
// И т. д. в цикле, пока не превзошли корня из N.
// 2 Этап. Часть из оставшиеся чисел после корня из N могут также быть простыми.
// Таким образом, нужно искать невычеркнутые числа после корня из N и для них также проверять делимость N.
//
// При нахождении очередного делителя на обоих этапах можно "уменьшить" N,
// т. е. N = N / p (если p - кратный делитель N, делим до тех пор, пока делится),
// чтобы уменьшить количество простых чисел для дальнейшего рассмотрения.

// Ограничимся ста миллионами
#define MAX_VAL 100000000

void main (void)
{
    int max_val;
    cout << "Enter number: ";
    cin >> max_val;
    if (max_val > MAX_VAL || max_val < 2)
    {
        cout << "Wrong limits";
        return;
    };
    // Поиск простых ведем до корня из max_val
    int sqrt_max_val = (int)sqrt((double)max_val);
    // Признаки "вычеркнутости" чисел (элементы 0 и 1 не используются)
    deque<bool> flags (max_val+1, false);  // Массив признаков вычеркнутости чисел.
    // flags означает, вычеркнуто ли i или нет (true - вычеркнуто, false - нет).
    // Первоначально все числа не перечеркнуты
    int current_value = 2;  // Текущее простое число
    do
    {
        // Проверим делимость на текущее простое число
        if (max_val % current_value == 0)
        {
            cout << current_value << endl;
            do
                max_val /= current_value;
            while (max_val % current_value == 0);
            sqrt_max_val = (int)sqrt((double)max_val);
        }
        // Вычеркиваем все числа, кратные current_value, начиная с его квадрата
        for (int i = current_value * current_value; i <= max_val; i += current_value)
            flags = true;
        // Ищем следующее невычеркнутое число
        for (++current_value; current_value <= sqrt_max_val && flags[current_value]; ++current_value) ;
    } while (current_value <= sqrt_max_val);
    // Проверим все невычеркнутые числа больше корня из N
    for (current_value = sqrt_max_val+1; current_value <= max_val; ++current_value)
        if (!flags[current_value] && max_val % current_value == 0)
        {
            cout << current_value << endl;
            do
                max_val /= current_value;
            while (max_val % current_value == 0);
            sqrt_max_val = (int)sqrt((double)max_val);
        };
};

Для перехода на С, что, как я понял, требуется автору темы, меняем cout и cin на printf и scanf, а deque<bool> flags на char *flags.
28K
12 августа 2007 года
Vladimir.
12 / / 03.08.2007
to Draconit
Цитата:
Разве? Вот к примеру число 15, у него 2 простых делителя 3 и 5, но если мы будем искать до значения квадратного корня (а он равен 3,873), то мы упускаем из виду 5. Или я что-то неправильно понял?


нет, это я неправильно написал (недописал). должно быть:

Цитата:
таким образом проверять простые делители следует от 2 до значения квадратного корня из n включительно,и для сложного числа n в указанном промежутке обязательно найдеться простой делитель;


например, 657: корень(657)<25, делителители в промежутке от 2 до 25 : 3, кратность равна двум.
657/(3*3) =73;
корень(73)<9, делителей в промежутке от 2 до 9 нет, следовательно 73 - простое;
ответ: разложение 657 = 3*3*73, делители 3 и 73.

P.S. тема еще актуальна?


Цитата:
cheburator писал :
Этот код всех порвет - однозначно
К примеру, 99 999 997 = 1297 * 77101. Подсчитано за 40 секунд на Pentium 4 2,4 GHz. Кто быстрее?


Я. Смотри сообщение номер пять.

16K
13 августа 2007 года
Draconit
39 / / 10.08.2007
to cheburator Сначала, как только за задачу сел, хотел с помощью решета Эратосфена сделать, нашел код на С++, но не понял:(
А за код с объяснением большое спасибо.
350
14 августа 2007 года
cheburator
589 / / 01.06.2006
Цитата: Vladimir.

Я. Смотри сообщение номер пять.


Да, согласен, действительно твой алгоритм лучше.
Только неплохо бы его документировать и обосновать.

Если тема еще актуальна, можно предложить усовершенствовать вариант Vladimir'а: там перебираются все нечетные числа, кроме 2, можно сделать, скажем, перебор всех чисел, не делящихся на 2, 3 и 5, кроме самих 2, 3 и 5. Для этого перебор числа k вести особым образом. Число операций снижается примерно вдвое. Хотя в этом мало необходимости, т. к. алгоритм Vladimir'а и так быстр.
Код во вложении.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог