Давайте будем точными: 12 с половиной.
Отличный пример, спасибо!
На лекции было дано домашнее задание: написать программу,которая вычисляет число в n степени,где n >0 и целое. вот мой вариант:
{программа возводит число х в степень n,когда n∈N}
program task1;
begin
writeln('Введи основание степени');
var x := ReadInteger;
writeln('введи показатель степени');
var n := ReadInteger;
writeln('Значение выражения = ', exp(ln(x) * n))
end.
еще есть вариант менее эффективной программы через цикл for:
program task2;
begin
writeln('Введи основание степени');
var x := ReadInteger;
writeln('введи показатель степени');
var n := ReadInteger;
var k, i: integer;
k := 1;
for i := 1 to n do
k := k * x;
writeln('Искомое число = ', k)
end.
Задание было другое - сделать это за наименьшее количество умножений
То же задание. Найти a в натуральной степени n за минимальное число умножений. Использован рекурентный алгоритм:
// Задание с лекции. Нахождение a в натуральной степени n за наименьшее число умножений на основе рекурентного алгоритма.
program TaskPower;
function powerm(a, n: integer; var i: integer): biginteger ;
// a - исходное число. n - желаемая степень числа. i - счётчик затраченных умножений.
begin
if n = 1 then // Точка выхода из рекурсии.
result := a
else
if (n mod 3) = 0 then // Случай для n кратно 3
begin
var f := powerm(a, n div 3, i);
i += 2;
result := f * f * f;
end else
if (n mod 2) = 0 then // Случай для n кратно 2
begin
var f := powerm(a, n div 2, i);
i += 1;
result := f * f;
end else
begin// Случай для n не кратно 2 или 3
i += 1;
result := powerm(a, n - 1, i) * a;
end;
end;
begin
var a := readlninteger('Введите исходное число: a=');
var n := readlninteger('Введите степень числа ( n<= 0 - запуск демонстрационного режима): n=');
var ni := 0; // счётчик умножений
if n > 0 then
begin
var r := powerm(a, n, ni);
writelnformat('Исходное число: a={0}; Степень числа: n={1}; Кол-во использованных умножений: {2}; Результат вычислений:{3}; ', a, n, ni, R);
end else
begin
Writeln('Для заданного числа будут выведены 100 первых степеней.');
sleep(2000);
for var i := 1 to 100 do
begin
var R := powerm(a, i, ni);
writelnformat('Исходное число: a={0}; Степень числа: n={1}; Кол-во использованных умножений: {2}; Результат вычислений:{3}; ', a, i, ni, R);
ni := 0;
end;
end;
end.
Task-Power.pas (1,6 КБ)
Иные разложения делаются оптимально для n кратных 5 а не 3 То есть, этот алгоритм - неоптимальный, хотя и лучше степеней 2
begin
writeln('Введите число ');
var a := readreal;
writeln('Введите степень ');
var b := readinteger;
var itog:= 1.0;
var count:=0;
var b1:=b;//сохранить степень для вывода
while b > 0 do
begin
if (b mod 2 = 0) then
begin
a *= a;
b := b div 2;
count+=1;
end
else
begin
itog*= a;
dec(b);;
count+=1;
end;
end;
WriteFormat('Число - {0} степень - {1} результат - {2} минимальное количество операций - {3}',a,b1,itog,count-1);
end.
я модернизировал прошлый алгоритм, исправил баг,но уже отправил , поэтому приходится второй раз это делать( раньше выводил неверно, когда степень числа - степень тройки и при выводе не всегда правильно было)
begin
writeln('Введите число ');
var a := readreal;
writeln('Введите степень ');
var b := readinteger;
var itog := 1.0;
var count := 0;//количество a( кол-во умножений минус 1)
var b1 := b;//сохранить степень для вывода
var a1:=a;
while b > 0 do
begin
if (b mod 2 = 0) then
begin
a *= a;
b := b div 2;
count += 1;
end
else
if (b mod 3 = 0) then
begin
a *= a*a;
b := b div 3;
count += 2;
end
else
begin
itog *= a;
dec(b);
count += 1;
end;
end;
WriteFormat('Число - {0} степень - {1} результат - {2} минимальное количество операций - {3}', a1, b1, itog, count - 1);
end.
Еще один вариант, использован метод динамического программирования
[code]function pow(a:integer; n:integer; var col:integer):int64; //Return a^n (a and n - integers), push to ‘col’ the count of operations begin var arr: array [1…100] of int64; //В массиве будем хранить уже вычисленные степени var res:int64 := a; //Здесь будем накапливать результат arr[1] := a; var st := n; //Сколько степеней нам еще осталось var i := 1; //Текущая степень var j := 1; //Индекс в массиве степеней while (i+i<=n) do //Пока можем вычислять степени, являющиеся квадратами предыдущих степеней - вычисляем begin j+=1; arr[j] := arr[j-1]*arr[j-1]; //Вычисляем следующую степень col+= 1; i+=i; //Удваиваем степень, т.к мы нашли квадрат end; st-= i; //Сколько еще осталось res := arr[j]; //Результат предыдущих вычислений while (st > 0) do begin i := 1; j := 1; while (i+i < st) do begin i +=i; j +=1; end; res *= arr[j]; col+=1; st-=i; end; result := res; end;
begin var i,a,b:integer; writeln(‘Введите число’); read(a); writeln(‘Введите степень’); read(b); writeformat(’{0}^{1}={2}, количество операций - {3}’, a, b, pow(a,b,i), i); end.[/code]
Замена n-ого бита на 1.
begin
var b,a,n:byte;
read(a,n); // вводим число и номер бита
n:=1 shl (n-1); // находим десятичное число, которое в двоичной записи имеет только один бит равный единице на n-ом месте
b:=a or n; // при этом n-ый бит исходного числа в двоичном коде станет равным 1
write(b);
end.
Замена n-ого бита на 0.
begin
var b,a,n:byte;
read(a,n);
n:=1 shl (n-1);
n:= not(n); // всё до этого так же, как и в прошлый раз, но теперь инвертируем полученое число, получая значение, которое в двоичной c.c представляет собой последовательность, состоящую только из единиц, кроме n-ого бита
b:=a and n;
write(b);
end.
Инвертирование n-ого бита.
begin
var b,a,n,m:byte;
read(a,n);
m:=1 shl (n-1);
if a shr (n-1) mod 2 = 0 then // если исходное число при битовом смещении вправо на n-1 становиться четным, значит, n-ый бит равен 0 и мы с помощью or делаем его равным 1
b:=a or m
else
begin
m:= not(m);// а если число при смещении получилось нечетным, мы заменяем нужный бит на о
b:=a and m;
end;
write(b);
end.
Так как на изменение бита на 1 и на 0 уже есть решения. Я предложу решение на инвертирование(немного другое).
[code]program byteinvert;
var b: byte; n: integer;
begin writeln(‘введите число и бит ,который нужно изменить’); read(b, n); var a := 1 shl (n - 1); a := not (a); b := (not (a) or b) and (not (b) or a);//эквиваленция writeln(b); end.[/code]
Решение задачи про треугольник. Кратко опишу алгоритм, возможно он не самый лучший. Если точка находится внутри треугольника, то, если провести к ней из вершин треугольника отрезки, то получится, что она разбила треугольник на 3. Следовательно, сумма площадей этих треугольников равна площади большого. Применяя несколько раз формулу Герона, получим искомый результат.
Function Def(var a,b,c,d:real):real; begin Def:=sqrt((b-a)(b-a) + (c-d)(c-d)) end; Function S(var a,b,c,p: real):real; begin S:=sqrt(p*(p-a)(p-b)(p-c)) end; begin var Xa:=ReadReal; var Ya:=ReadReal; var Xb:=ReadReal; var Yb:=ReadReal; var Xc:=ReadReal; var Yc:=ReadReal; var Xs:=ReadReal; var Ys:=ReadReal; var AB:=Def(Xa,Xb,Ya,Yb); var BC:=Def(Xc,Xb,Yc,Yb); var AC:=Def(Xa,Xc,Ya,Yc); var SA:=Def(Xa,Xs,Ya,Ys); var BS:=Def(Xs,Xb,Ys,Yb); var SC:=Def(Xs,Xc,Ys,Yc); var Pabc:=(AB+BC+AC)/2; var Sabc:=S(Pabc,AB,AC,BC); var Psab:=(AB+BS+SA)/2; var Ssab:=S(Psab,SA,AB,BS); var Psac:=(AC+SC+SA)/2; var Ssac:=S(Psac,SA,AC,SC); var Pscb:=(BC+BS+SC)/2; var Sscb:=S(Pscb,BS,BC,SC); writeln(Sabc=Ssac+Sscb+Ssab) end.
Приведу алгоритм решения задачи про четырехугольник. Очевидно, что нас не устраивает вариант, когда АВ пересекается с СD внутри этого “четырехугольника”,т.е когда порядок АСВD. Рассмотрим возможности пересечения AВ и СD. Точка пересечения М может находиться либо между отрезками АD и ВС, либо вне этих отрезков. Если она внутри, то четырехугольника не существует, если она вне, или прямые параллельны, то четырехугольник возможен. Если нарисовать картинку, то факт очевиден.
Дальше просто пишем уравнение всех прямых, находим точку пересечения прямых АВ и СD, а потом проверяем: если подставить координаты точки М в уравнения прямых АС и ВС, и при этом получится, что одна из левых частей уравнений больше нуля, а другая меньше, то четырехугольника не существует. В противном случае такой четырехугольник существует.
P.S. Адекватно реализовать алгоритм в программу не получилось, поэтому привел только сам алгоритм)
Хотелось бы довести до формул
Еще одно решение задачи про треугольник, немного отличающееся от предоставленного выше
program op_task1;
begin
Var Xa, Ya, Xb, Yb, Xc, Yc: real; write('Введите Xa, Ya >> '); readln(Xa, Ya); write('Введите Xb, Yb >> '); readln(Xb, Yb); write('Введите Xc, Yc >> '); readln(Xc, Yc);
//Найдем общую площадь треугольника //Формула S=1/2[(x1-x3)*(y2-y3)-(x2-x3)(y1-y3)]
var So:=abs(1/2*((Xa-Xc)(Yb-Yc)-(Xb-Xc)(Ya-Yc)));
var Xm, Ym: real; write('Введите Xm, Ym >> '); readln(Xm, Ym);
//Найдем сумму треугольников, одна из вершин которой - исходная точка, а две другие - вершины треугольника //Всего таких треугольников будет 3
var S1:=abs(1/2*((Xa-Xm)(Yb-Ym)-(Xb-Xm)(Ya-Ym))); var S2:=abs(1/2*((Xa-Xc)(Ym-Yc)-(Xm-Xc)(Ya-Yc))); var S3:=abs(1/2*((Xm-Xc)(Yb-Yc)-(Xb-Xc)(Ym-Yc)));
var S:=S1+S2+S3;
//Проверяем, “складывается” ли из этих треугольников искомый
if S=So then println(‘Точка принадлежит треугольнику’) else println(‘Точка не принадлежит треугольнику’);
end.
На лекциях было предложено реализовать нерекурсивный вариант решения классической задачи про Ханои.
procedure Hanoi(f, t, w, n: integer);
begin
if n = 0 then
exit;
Hanoi(f, w, t, n-1);
WritelnFormat('Перенести с {0} на {1}.', f, t);
Hanoi(w, t, f, n-1);
end;
Если представить все возможные переносы дисков в виде дерева, можно заметить, что алгоритм использует инфиксный обход по нему. У меня получился такой вариант итерационного решения:
type
HanoiNode = auto class
f, t, w, n: integer;
function Shift: HanoiNode;
begin
WritelnFormat('Перенести с {0} на {1}.', f, t);
Result := Self;
end;
end;
procedure Hanoi(f, t, w, n: integer);
begin
var s := new Stack<HanoiNode>;
var disc := new HanoiNode(f, t, w, n);
while (s.Count > 0) or (disc.n > 0) do
begin
if disc.n > 0 then
begin
s.Push(disc);
// Условно принимаем в рассмотрение корень всего левого поддерева
disc := new HanoiNode(disc.f, disc.w, disc.t, disc.n - 1);
end
else begin
// Принимаем в рассмотрение корень и сразу выводим сообщение о переносе
disc := s.Pop.Shift;
// Условно принимаем в рассмотрение корень всего правого поддерева
disc := new HanoiNode(disc.w, disc.t, disc.f, disc.n - 1);
end;
end;
end;
Да, принимается. Только метод Shift какой-то странный - функция с побочным действием печати значения
В книге С.А.Абрамов. “Математические построения и программирование”, М., Наука, 1978 глава III параграф 5 приведен отличный разбор задачи “Ханойские башни”, в частности, избавление от рекурсии. Вообще книжечка полезная. Там и деревья и многое другое.