Получить все простые делители числа
Объясните пожалуйста как решить эту задачу, т.е. алгоритм действий, т.к. я не очень понимаю как и в каком порядке нужно решать.
Язык программирования не важен, мне главное алгоритм, желательно словами, т.к. я пока только разбираюсь в 2-ух языках: Паскаль и Си.
Объясните пожалуйста как решить эту задачу, т.е. алгоритм действий, т.к. я не очень понимаю как и в каком порядке нужно решать.
Язык программирования не важен, мне главное алгоритм, желательно словами, т.к. я пока только разбираюсь в 2-ух языках: Паскаль и Си.
1. Найти все простые числа до половины данного числа, для каждого их них проверить делитель или нет.
2. Найти все делители, выбрать из них простые числа.
2. получить следующее простое число,
если его нет, то находим новое простое число и добавляем в набор;
3. делим число на простое число
если делится, то делим наше число и к п1,
если не делится, то
если остаток ==1 - подсчет окончен,
в противном случае к п2
/**********************************************************
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);
}
#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();
}
Вроде же правильно?:)
2. Найти все делители, выбрать из них простые числа.[/quote]
я так понимаю это два метода решения поставленной задачи, правильно? вот против второго ничего не имею против, но насчет первого есть вопрос:
берем n=3 потом, половина данного числа 1.5, простых чисел являющихся делителями n нет в интервале от 1 до 1.5(ну или если округлить, то 2), тогда как же быть? ведь мы теряем 3.
ЗЫ: правда Draconit не считает их колво...
ЗЫ: правда Draconit не считает их колво...
ты это вообще к чему?;)
#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();
}
Ты слишком часто проверяешь четные числа на простоту...
[QUOTE=WidowMaker ]
Ну пошевили серым веществом, какое число дает 0 простых делителей?
ЗЫ: правда Draconit не считает их колво...
[/QUOTE]
Что к чему?
2. Ты писал Zorkus'у, что выполняя поиск до n/2 мы теряем простое n.
Я указал на то что достаточно ввести счетчик обнаруженных делителей числа, и если он в конце расчетов ==0, то число n - простой делитель самого себя....;)
2. Ты писал Zorkus'у, что выполняя поиск до n/2 мы теряем простое n.
Я указал на то что достаточно ввести счетчик обнаруженных делителей числа, и если он в конце расчетов ==0, то число n - простой делитель самого себя....;)
:D
мда...
отвечу тебе по пунктам.
1. я знаю и вижу и думаю остальные это видят и знают, а что это разве непонятно? человеку надо вообще-то указать хотя бы пример, чтобы он задумался. а теперь смотри если n=3, то пропускается число 3, которое что? правильно, которое обозначено как n, а значит пропускается n! так что [quote=WidowMaker]пошевили серым веществом[/quote];)
2. это я писал Zorkus'у и ждал ответа от него. мы теряем n по тому подходу, который он предложил и он про счетчик ничего не писал, так что подход неправильный. не следует лезть в разговор, тем более когда видно, что я обращаюсь к определенному собеседнику.
Если посмотришь на мой следующий мсж то я обратился к Draconit с предложением улучшить перебор.
Насчет
я не совсем тебя понял
ЗЫ: на счет серого вещества (читай подумай), не обижайся, эт я от скуки начинаю хамить;)
ЗЫ: на счет серого вещества (читай подумай), не обижайся, эт я от скуки начинаю хамить;)
[COLOR="Red"]Что ? От скуки ? Так вот : хамить ты здесь не будешь :mad: ни от скуки , ни от других своих недугов.Поверь мне.Следующее нарушение будет для тебя последним.[/COLOR]
Вижу перебор простых чисел идет до 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 простое.)
--------------------------------------------------------------------------------------
редактирование:
нет, это я неправильно написал. должно быть:
например, 657: корень(657)<25, делителители в промежутке от 2 до 25 : 3, кратность равна двум.
657/(3*3) =73;
корень(73)<9, делителей в промежутке от 2 до 9 нет, следовательно 73 - простое;
ответ: разложение 657 = 3*3*73, делители 3 и 73
Разве? Вот к примеру число 15, у него 2 простых делителя 3 и 5, но если мы будем искать до значения квадратного корня (а он равен 3,873), то мы упускаем из виду 5. Или я что-то неправильно понял?
А задачку кажется сделал:
#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();
}
Вроде на этот раз нормально?
и еще
я так понимаю ты сравниваешь, так тогда тебе надо == использовать.
Алгоритм решета Эратосфена приведен здесь:
http://forum.codenet.ru/showpost.php?p=198722&postcount=5
Этот алгоритм, правда, можно улучшить за счет того, что:
1. При вычеркивании чисел достаточно вычеркивать до корня из N (имеется в виду, для простых, не превосходящих корня из N, но вычеркиваются числа до N).
2. Приступая к вычеркиванию кратных очередного простого числа p, вычеркивание следует начинать с p^2.
#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;
};
#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.
нет, это я неправильно написал (недописал). должно быть:
например, 657: корень(657)<25, делителители в промежутке от 2 до 25 : 3, кратность равна двум.
657/(3*3) =73;
корень(73)<9, делителей в промежутке от 2 до 9 нет, следовательно 73 - простое;
ответ: разложение 657 = 3*3*73, делители 3 и 73.
P.S. тема еще актуальна?
Этот код всех порвет - однозначно
К примеру, 99 999 997 = 1297 * 77101. Подсчитано за 40 секунд на Pentium 4 2,4 GHz. Кто быстрее?
Я. Смотри сообщение номер пять.
А за код с объяснением большое спасибо.
Я. Смотри сообщение номер пять.
Да, согласен, действительно твой алгоритм лучше.
Только неплохо бы его документировать и обосновать.
Если тема еще актуальна, можно предложить усовершенствовать вариант Vladimir'а: там перебираются все нечетные числа, кроме 2, можно сделать, скажем, перебор всех чисел, не делящихся на 2, 3 и 5, кроме самих 2, 3 и 5. Для этого перебор числа k вести особым образом. Число операций снижается примерно вдвое. Хотя в этом мало необходимости, т. к. алгоритм Vladimir'а и так быстр.
Код во вложении.