Как найти максимальный делитель числа паскаль

0 / 0 / 0

Регистрация: 22.12.2012

Сообщений: 5

1

16.05.2013, 18:03. Показов 5372. Ответов 2


Студворк — интернет-сервис помощи студентам

вывести на экран максимальный делитель числа n, отличный от единицы и самого себя.



0



Ginar

13 / 13 / 21

Регистрация: 07.05.2013

Сообщений: 38

17.05.2013, 10:58

2

Лучший ответ Сообщение было отмечено axe1515 как решение

Решение

Pascal
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
Program delitel;
uses crt;
var  a : array [1..10000] of integer; 
    n, maxj, j: integer;
     i: byte;
BEGIN
CLRSCR;
i:=1;
Writeln('Vvedite n', ' ',n); {в приделе 10000}
read(n);
While i<n do beign
If  n mod i = 0 then begin 
  For j:=1 to 10000 do begin
  a[j]:=n/i;
 Write(a[j]);
END;
END;
i=i+1 {может быть и так i:=i+1}
END;
maxj:=a[i];
For j:=1 to 10000 do begin
If a[j]>maxj then maxj:=a[j];
END;
Writeln('Максимальный делитель n', maxj);
Readkey;
END.



0



Puporev

Почетный модератор

64287 / 47586 / 32739

Регистрация: 18.05.2008

Сообщений: 115,182

17.05.2013, 11:42

3

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
uses crt;
var n,d:integer;
    f:boolean;
begin
clrscr;
write('Введите натуральное число n=');
readln(n);
d:=n div 2;
f:=false;
while (d>1)and not f do
if n mod d=0 then
 begin
  write('Наибольший делитель=',d);
  f:=true
 end
else d:=d-1;
if not f then write('Это число простое, делители 1 и ',n);
readln
end.



0



Если сначала прикинуть, где вообще находятся делители любого числа, то вы обнаружите, что искать делители числа N следует лишь в диапазоне от 0 до N/2, плюс еще делитель N. Поясню на примере числа 36:

 Делители: 1,2,3,4,6,9,12,18 ... и 36. Как видите, все неизвестные делители находятся лишь в первой половине числа, т.е от 1 до N/2 плюс само N, т.е 36.

Это очевидно.

Следующий момент:

Раз мы ищем сумму всех делителей числа, то по логике вещей, те числа, что ближе к N будут иметь сумму делителей больше, чем те, что дальше. Но! Это не всегда так, поэтому в используемом ниже алгоритме диапазон поделен лишь поровну, чего в общем-то достаточно.

Я предложу такой алгоритм:

    int N = 20000;
    int dp_summ = 0, dp=0, ch = 0;

    for(int i=N/2;i<=N;i++)
    {
        int ost = (i%10);
        if(dp>2 && (ost==1 || ost==3 || ost==7 || ost == 9)) continue;

        int curr = 0, curr_dp=0;
        for(int j=1;j<=i/2;j++) if(i%j==0) {curr+=j; curr_dp++;}
        curr+=i;curr_dp++;
        if(curr>dp_summ) {dp_summ=curr; dp=curr_dp; ch = i;}
    }

    printf("Digit is %i   have sum of dividers = %i, diveders = %in",ch,dp_summ,dp);

Также в алгоритм можно внедрить какой-либо другой алгоритм для ускорения. Например, алгоритм Люка для проверки числа на простоту. Но это уже пускай останется вам в качестве самостоятельной работы =)

Задача ваша среднего уровня, интересная даже малость) Вот мне самому интересно найти наиболее корректное решение. Вся обоснованная критика в адрес приведенного выше алгоритма только приветствуется.

Содержание

Математика и числа

Чётность/нечётность чисел

if Odd (Number) then 
  writeln (Number, ' нечётно')
else
  writeln (Number, ' чётно');

Делимость (кратность) чисел

if Number mod 3 = 0 then
  writeln (Number, ' делится на 3 без остатка');

Делиться без остатка — означает кратность.

Наибольший Общий Делитель

(НОД, англ. Greatest Common Divisor)

{ Евклид (Euclidus) }
function GCD (A: integer;  B: integer): integer;
begin
    while (a <> 0) and (b <> 0) do
       if a >= b then
         a := a mod b
       else 
         b := b mod a;
    GCD := a + b; { один - ноль }
end;

Наименьшее Общее Кратное

(НОК, англ. Least Common Multiplier)

function LCM (A: integer;  B: integer): integer; 
begin
     LCM := a * b div GCD (a, b)
end;

Степень

Для целых чисел

function Power(Base, N: integer): longint;
{ Base - основание , N - степень }
var
   Result: longint;
   i: word;
begin
   Result := 1; { придаём начальное значение }
   for i := 1 to N do
     Result := Result * Base;
 
   Power := Result;
end;

Для вещественных чисел

Возвести A в степень N. Ограничения: [COLOR=red]только для A > 0[/COLOR]

function PowerExp (A, N: real): real;
begin
   if A > 0 then
     PowerExp := Exp ( N * Ln (A) )
   else 
     PowerExp := 0;
end;

Факториал

function Factorial(N: word): longint;
var
   Result: longint;
   i: word;
begin
   Result := 1;
   for i := 1 to N do 
     Result := Result * N;
 
   Power := Result;
end;

С использованием рекурсии

function Factorial (N: word): longint;
begin
   if N = 0 then
     Factorial := 1 
   else 
     Factorial := N * Factorial (N - 1);
end;

Вещественный и целый типы

Round — Округляет значение вещественного типа до значения целого типа, округляя.
Trunc — Округляет значение вещественного типа до значения целого типа, отбрасывая дробную часть.
Frac — Возвращает дробную часть аргумента.
Int — Возвращает целую часть аргумента.

   var
       r : real;
     begin
       r := Round ( 123.456);  {    123 }
       r := Round ( 123.778);  {    124 }
       r := Trunc ( 123.456);  {    123 }
       r := Trunc (-123.778);  {   -123 }
       r := Frac  ( 123.456);  {  0.456 }
       r := Int   ( 123.456);  {  123.0 }
       r := Int   (-123.456);  { -123.0 }
     end.

Случайные числа

Процедура Randomize — инициализирует генератор чисел.
Функция Random (N) выдает целочисленные значения в диапазоне от 0 до N-1 !
Например, чтобы сгенерировать число X в диапазоне -N..N , пишем так:

  Randomize;
  X := Random (N + 1) - 2 * N;

Если не написать сначала Randomize; , то будут генерироваться одни и те же числа.

Как проверить простое ли число?

function isPrime(X: word): boolean;
var
i: integer;
Begin
     isPrime:=false;
     if not odd(x) and (x<>2) { проверяем на чётность  }
          then exit;
     i:=3;
     while i <= sqrt(x) do { проверяем только нечётные }
     begin
          if x mod i = 0 then Exit;
          inc(i,2);
     end;
 
     isPrime:=true;
End;

Разложение числа на множители

procedure Factorization(x: word);
var i: word;
 
 procedure DivX; { делим на простое число, пока делится без остатка }
 begin
      while (x>1) and (x mod i = 0) do
      begin
           write(i:4);
           x:= x div i;
      end;
 end;
 
begin
     i:=2;
     DivX;
     i:=3;
     while (i < x div 2) do
     begin
           DivX;
           inc(i,2); { <=> i:=i+2; только нечётные числа }
     end;
     if x>1 then writeln(x:4);
end;

Приближённое представление числа в виде дроби

VAR p,q,qmax:integer;
    d, r, min: real;
BEGIN
   write('r, qmax=');
   readln(r, qmax); { r - не целое число, qmax - кол-во итераций (циклов) }
   p:=0; q:=1; min:=r;
   REPEAT
     IF p / q < r
          THEN inc(p)
          ELSE inc(q);
     d:=abs(r-p/q);
     IF d < min THEN
     BEGIN
          min:=d;
          writeln(p:7,'/',q)
     END
   UNTIL (q >= qmax) OR (d = 0);
   readln;
END.

Как работать с отдельными битами?

FUNCTION IsBitOn (n: word; b : BYTE): BOOLEAN; { Проверяем, установлен ли бит }
BEGIN 
     isBitOn:=((n SHR b) AND 1) = 1
END;
 
PROCEDURE SetBitOn (VAR n: Word; b: BYTE); { Устанавливаем бит }
BEGIN
     N:= N OR (1 SHL b)
END;
 
PROCEDURE XORBit (VAR n: Word; b: BYTE); { Переключаем бит }
BEGIN
     N:= N XOR (1 SHL b)
END;

Как узнать из каких цифр состоит целое число?

Var X : Integer;
Begin
 X:=12345;
 Writeln('Число состоит из таких цифр:');
 While X <> 0 Do
  Begin
   Writeln(X Mod 10);
   X:=X Div 10;
  End;
End.

Как быстро делить/умножать числа на степень двойки ?

Как известно, опрерации умножения и деления занимаю много машинного времени. Если требуется скорость, то целесообразно использовать логические сдвиги:

i:=i shl 1; { i:=i * 2^1}
i:=i shl 2; { i:=i * 2^2}
{и т.д.}
i:=i shr 1; { i:=i div 2^1}
i:=i shr 2; { i:=i div 2^2}
{и т.д.}

Примечание: корректно работает только с целыми беззнаковыми типами (word, byte…)!
Если производить эти операции со знаковыми типами, то бит знака тоже сдвигается и в результате
число может поменять свой знак!

Более быстрое разложение числа на множители

В методе, описанном ранее, количество проверок пропорционально sqrt(N), т.е. для разложение числа порядка 1012 потребуется около 106 операций, причем используется деление!
Существуют методы поиска делителей, которые справляются со своей задачей намного быстрее (без операций деления).
В методе Ферма предполагается, что N — нечетное число, причем N = uv. Попробуем подобрать такие числа X и Y, что будет выполняться:
N = p2 — q2. Обозначим u = (p + q) / 2 и v = (p — q) / 2.
Будем пытаться приблизить числа p и q с разных сторон, чтобы выполнялось N = p2 — q2.
Итак, сам алгоритм:

  • Присвоим x = 2 * trunc(sqrt(N)) + 1, y = 1, r = sqr(trunc(sqrt(N))) — N (во время выполнения алгоритма числа x, y и r будут соответствовать 2p + 1, 2q + 1 и p2 — q2 — N)

  • Если r = 0, то выполнение алгоритма заканчивается. Имеем N = ((x-y)/2)((x+y-2)/2) и (x-y)/2 — наибольши делитель числа N.

  • Присвоить r = r + x, x = x + 2 (шаг по x)

  • Присовить r = r — y, y = y — 2 (шаг по y). Делать этот шаг, пока r > 0.

  • Перейти к проверке r = 0

Так как все действия алгоритма — это сложения и вычитания, то они на компьютере выполняются очень быстро. В результате работы алгоритма будет получено одно число — наибольший делитель числа N. Замечание: данный алгоритм лучше использовать для поиска больших делителей, нежели для маленьких!

{$N+, E+}
 
function FermaFactorization (N : Comp) : Comp;
 
var
  X, Y, R, Z, ZZ : Comp;
 
begin
 Z := Sqrt(N);
 ZZ := Trunc (Z);
 X := 2 * ZZ + 1;
 Y := 1;
 R := Sqr (ZZ) - N;
 while (R <> 0) do
  begin
   R := R + X;
   X := X + 2;
   repeat
    R := R - Y;
    Y := Y + 2;
   until R <= 0;
  end;
 FermaFactorization := (X - Y) / 2;
end;
 
begin
 Writeln (FermaFactorization(917979909) : 0 : 0);
end.

Методика
решение задания № 25 ЕГЭ 2022 в программе
PascalABC.NET 3.2

Автор:

Василенко
И.А., учитель математики и информатики МБУ «Школа № 33» г. Тольятти Самарской
области

Теоретический
материал, который необходимо повторить:

  1. функции
    целочисленного деления:
    mod, div.
  2. описание
     оператора условия
    ifthenelse …;
  3. описание
    операторов повтора: с предусловием, с постусловием, с параметром;
  4. описание
    алгоритма нахождения максимального и минимального числа.

Задача 1. ( Информатика.
Единый         Государственный Экзамен. Готовимся к итоговой аттестации :
[учебное пособие] / В.Р. Лещинер, С.С. Крылов. – М.: Издательство
«Интеллект-Центр», 2022)«Подготовка к ЕГЭ по информатике», 2022
)

Напишите программу, которая ищет среди целых чисел,
принадлежащих отрезку [400; 450], простые числа, то есть числа, не имеющие
натуральных делителей, не считая единицы и самого числа. Запишите эти числа в
таблицу на экране с новой строки в порядке возрастания.

Описание
переменных (тип переменных
: integer):

х- перебирает все
числа от 400 до 450

i
перебирает все делители для числа х от 1 до х

n— хранит
количество делителей  числа х

Листинг
программы

var x,i,n:integer;

begin

  x:=400;{первоначальное
значение х}

  n:=0;

    while x<=450 do
begin
{перебираем числа до 450 включительно}

        for i:=1
to x do begin {перебираем
делители от 1 до x}

        if (x mod
i)=
0 then   n:=n+1;
{считаем число делителей для числа х}end;

     if n=2 then writeln
(
‘x=’,x,‘   n=’,n);

     n:=0;{обнуляем
число делителей для следующего числа х}

     x:=x+1;{берем
следующее число}

     end;
end.

Результат
работы программы

x=401  
n=2

x=409  
n=2

x=419  
n=2

x=421  
n=2

x=431  
n=2

x=433  
n=2

x=439  
n=2

x=443  
n=2

x=449  
n=2

Ответ на
экзамене:

401

409

419

421

431

433

439

443

449

Задача 2. (Информатика. Единый          
Государственный Экзамен. Готовимся к итоговой аттестации : [учебное пособие] /
В.Р. Лещинер, С.С. Крылов. – М.: Издательство «Интеллект-Центр»,
2022)«Подготовка к ЕГЭ по информатике», 2022
)

Напишите программу,
которая ищет среди целых чисел, принадлежащих отрезку [550; 600], простые
числа, то есть числа, не имеющие натуральных делителей, не считая единицы и
самого числа. Запишите эти числа в таблицу на экране с новой строки в порядке
возрастания.

Листинг
программы

var
x,i,n:integer;

begin

  x:=550;{первоначальное
значение х}

  n:=0;

    while x<=600 do begin {перебираем
числа до 600 включительно}

        for i:=1 to x do
begin
{перебираем делители от 1 до x}

        if (x mod i)=0 then   n:=n+1; {считаем
число делителей для числа х}
end;

     if n=2 then writeln (x);

    
n:=0;{обнуляем число делителей для следующего
числа х}

     x:=x+1;{берем
следующее число}

     end;end.

Ответ на экзамене:

557

563

569

571

577

587

593

599

Задача 3. (Демо-версия
2022
)

Пусть М – сумма минимального и
максимального натуральных делителей целого числа, не считая единицы и самого
числа. Если таких делителей у числа нет, то значение М считаем равным 0.

Напишите программу, которая перебирает
целые числа, большие 700000, в порядке возрастания и ищет среди них такие, для
которых значение М оканчивается на 8. Выведите первые пять найденных чисел и
соответствующие им значения М.

Формат вывода: для каждого из пяти таких
найденных чисел в отдельной строке сначала выводится само число, затем –
значение М.

Строки выводятся в порядке возрастания
найденных  чисел.

Количество строк для ответа избыточно.

Работа
с условием задачи

  1. Обратим
    внимание, что будем искать минимальный и максимальный делители, не
    считая 1 и самого числа х
    .
  2. Сумму
    минимального и максимального делителей хранит переменная М. Необходимо
    найти первые пять чисел х (контрольная сумма
    s, при
    выполнении условия
    M mod
    10=8, должна увеличиваться на единицу, то есть включаем счетчик
    s:=s+1), в
    порядке возрастания, которые больше числа 700000.
  3. Следует
    обратить внимание на формат вывода:
    для каждого
    из пяти таких найденных чисел в отдельной строке сначала выводится
    само число х, затем – значение М.

Скрытые
условия ( для нас это ошибки) следует отследить на малых числах.
Рассмотрим
работу алгоритма на меньших значениях: пусть первоначальное значение х больше 5
(совершенно произвольно взяли число 5). Построим таблицу делителей для чисел
больших 5:

Число
х

Все
делители

min

max

М:=min+max

М
mod
10 =8?

Вывести

 х

Вывести
М

k

6

1,
2, 3, 6

2

3

5

7

1,
7

0

0

0

8

1,
2, 4, 8

2

4

6

9

1, 3, 9

3

0

3

10

1, 2, 5, 10

2

5

7

11

1,
11

0

0

0

12

1,
2, 3, 4, 6, 12

2

6

8

+

12

8

0+1=1

13

1,
13

0

0

0

14

1,
2, 7, 14

2

7

9

15

1,
3, 5, 15

3

5

8

+

15

8

1+1=2

16

1,
2, 4, 8, 16

2

8

10

17

1,
17

0

0

0

Для
числа 9
 найдется один! делитель (в
программе необходимо предусмотреть условие, что минимальный делитель <> максимальному).
Программа завершает перебор чисел при
s=5,
то есть находит пять чисел х, для которых сумма максимального (<>
x)
и минимального ( <>1) делителей оканчивается на 8. На экране выводятся
пять пар в порядке возрастания х: число х и число М.

Предлагаем
разбить задачу на подзадачи:

1)    
составим программу, которая находит
делители (согласно условию) для одного числа, среди них находит максимальный и
минимальный делитель (
min<>max), сумму минимального и максимального
делителя (М) и проверяет условие
M
mod 10=8.

2)    
используя, структуру повтора с
постусловием организуем подсчет контрольной суммы и обнуление некоторых переменных:

max:=0;
min:=x;M:=0;d:=0;

при следующем значении х (х:=х+1).

REPEAT

      
max:=0; min:=x;M:=0;d:=0;

   

       
if M mod
10=8 then  begin

       
writeln  (x, ‘   ‘, M); s:=s+1; end; {увеличиваем контрольную сумму s}

    
n:=0;{обнуляем число делителей для следующего
числа х}

     x:=x+1;{берем
следующее число}

  UNTIL s>=5{выводим
5 пар (x, M)}

…  

Листинг
программы (при х=6)

var x,i,n,max,min,M, d:integer;

 begin

 x:=6;{первоначальное
значение х большее 5}

  n:=0; max:=0; min:=x;

    for i:=2 to x-1 do begin{перебираем
делители от 2 до (x-1)для числа х}

     if (x mod i)=0 then begin

    
n:=n+1;{считаем число делителей для
числа х}

     d:=i;{переменная хранит текущий делитель}

     {осуществляем поиск макс и мин делителя}

     if d<=min then min:=d;

      
if d>=max then max:=d;

       writeln (i,‘  ‘,n); {выводим
текущее значение делителя и текущее значение n}

      end;end;

     
M:=min+max;

       
if M mod
10=8 then  writeln (x, ‘   ‘, M) else writeln (‘M=0’);

       
end.

Результат работы программы

В
результате у нас первый делитель  — это 2, а второй делитель – это 3.

М=0,
так как (2+3)
mod
10 =5.

Если
в программе х:=12, то результат работы программы следующий:

Листинг
программы (при х
>5)

var x,i,k,n,max,min,M,d,s:integer;

    begin

 x:=6;{первоначальное
значение х большее 5}

 s:=0; {контрольная сумма, которая накапливает
количество чисел}

    REPEAT

      
max:=0; min:=x;M:=0;d:=0;

    for i:=2 to x-1 do begin{перебираем
делители от 2 до (x-1)для числа х}

     if (x mod i)=0 then begin

  
  
n:=n+1;{считаем число делителей для
числа х}

     d:=i;{переменная хранит текущий делитель}

     {осуществляем поиск макс и мин делителя}

     if d<=min then min:=d;

      
if d>=max then max:=d;

      
{writeln (i,’  ‘,n);{выводим текущие значения делителя и n}

      end;end;

           
if min<>max then M:=min+max;

       
if M mod
10=8 then  begin

       
writeln 
(x,
‘  
,
M); s:=s+
1; end; {увеличиваем контрольную сумму s}

    
n:=0;{обнуляем число делителей для следующего
числа х}

     x:=x+1;{берем
следующее число}

  UNTIL s>=5{выводим
5 пар (x, M)}    

    END.

Результат
работы программы

Переменную
n (подсчет
делителей в окончательной программе уберем).

Листинг
программы (х
>
700000)

var
x,i,k,max,min,M,d,s:integer;

    begin

 x:=700001;{первоначальное
значение х большее 700000}

 s:=0; {контрольная сумма, которая накапливает
количество чисел}

    REPEAT

      
max:=0; min:=x;M:=0;d:=0;

    for i:=2 to x-1 do begin{перебираем
делители от 2 до (x-1)для числа х}

     if (x mod i)=0 then begin

      d:=i;{переменная
хранит текущий делитель}

     {осуществляем поиск макс и мин делителя}

     if d<=min then min:=d;

      
if d>=max then max:=d;

      
{writeln (i,’  ‘,n);{выводим текущие значения делителя и n}

      end;end;

           
if min<>max then M:=min+max;

       
if M mod
10=8 then  begin

       
writeln 
(x,
‘  
,
M); s:=s+
1; end; {увеличиваем контрольную сумму s}

     x:=x+1;{берем
следующее число}

    UNTIL s>=5{выводим
5 пар (x, M)}    

    END.

Результат
работы программы

Ответ
на экзамене:

700005

233338

700007

100008

700012

350008

700015

140008

700031

24168

Успехов
в учебе!

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

Примечание 1: делителем натурального числа a называется натуральное число b, на которое a делится без остатка. То есть выражение «b – делитель a» означает: a / b = k, причем k – натуральное число.

Примечание: нетривиальным делителем называется делитель, который отличен от 1 и от самого числа (так как на единицу и само на себя делится любое натуральное число).

Решение. Пусть ввод с клавиатуры осуществляется в переменную n. Попробуем решить задачу перебором чисел. Для этого возьмем число на единицу меньшее n и проверим, делится ли n на него. Если да, то выводим результат и выходим из цикла с помощью оператора break. Если нет, то снова уменьшаем число на 1 и продолжаем проверку. Если у числа нет нетривиальных делителей, то на каком-то шаге проверка дойдет до единицы, на которую число гарантированно поделится, после чего будет выдан соответствующий условию ответ.

Хотя, если говорить точнее, следовало бы начать проверку с числа, равного n div 2 (чтобы отбросить дробную часть при делении, если n нечетно), так как ни одно натуральное число не имеет делителей больших, чем половина это этого числа. В противном случае частное от деления должно быть натуральным числом между 1 и 2, которого просто не существует.

Данная задача также решается через for, но через другую его разновидность, и теперь счетчик будет убывать от n div 2 до 1. Для этого do заменится на downto, при позиции начального и конечного значений остаются теми же.

Алгоритм на естественном языке:

1)      Ввод n;

2)      Запуск цикла, при котором i изменяется от n div 2 до 1. В цикле:

  1. Если n делится на i (то есть, остаток от деления числа n на i равен 0), то выводим i на экран и выходим из цикла с помощью break.

Код:

  1. program GreatestDiv;
  2. var
  3. i, n: word;
  4. begin
  5. readln(n);
  6. for i := n div 2 downto 1 do begin
  7. if n mod i = 0 then begin
  8. writeln(i);
  9. break
  10. end
  11. end
  12. end.

Кстати, у оператора ветвления if в цикле отсутствует else-блок. Такой условный оператор называется оператором ветвления с одной ветвью.

Понравилась статья? Поделить с друзьями:
  • Как найти массовый состав соединения
  • Как найти уникальных клиентов
  • Как найти сопротивление нулевой последовательности кабеля
  • Как найти свой компьютерный номер эйвон
  • Как найти на алиэкспресс реплики кроссовок