Осваиваем Python по-быстрому №2 (задачи)

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 12 дек 2021, 13:23

Olej писал(а):
09 дек 2021, 19:17
Комплексная математика.
Q: Одно и то же комплексное значение может представляться в 2-х различных формах:
- алгебраическая (координатная) форма z = a + j * b, когда вещественная часть и мнимая часть являются проекциями на соответствующие оси координат 2D плоскости X и Y
- экспоненциальная форма z = |z| * exp( j * φ ), где модуль (длина вектора) |z| = sqrt( a2 + b2 ), а φ (фаза) — угол поворота вектора, отсчитываемый против часовой стрелки относительно оси X.
Напишите краткий тест преобразование нескольких комплексных значений в экспоненциальную форму, и обратно из экспоненциальной формы в алгебраическую, и сравнить с исходным значением.
complex.3.jpg
complex.3.jpg (12.48 КБ) 1193 просмотра
A:

Код: Выделить всё

#!/usr/bin/python3
from cmath import sqrt, polar, phase, exp, pi

z = (0, -3, 2.0, 1j, -sqrt(3j), 4j,
     2 + 3j, 4.0 + 1j, -3 - 3j, sqrt(2) - 1j )

for x in z:
   print("{} => {} : {}*exp(j*{}*π) => {}".
         format(x,polar(x), abs(x), phase(x), abs(x)*exp(1j*phase(x))))
Результат:

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./complex.3.py
0 => (0.0, 0.0) : 0*exp(j*0.0*π) => 0j
-3 => (3.0, 3.141592653589793) : 3*exp(j*3.141592653589793*π) => (-3+3.6739403974420594e-16j)
2.0 => (2.0, 0.0) : 2.0*exp(j*0.0*π) => (2+0j)
1j => (1.0, 1.5707963267948966) : 1.0*exp(j*1.5707963267948966*π) => (6.123233995736766e-17+1j)
(-1.224744871391589-1.2247448713915892j) => (1.7320508075688772, -2.356194490192345) : 1.7320508075688772*exp(j*-2.356194490192345*π) => (-1.224744871391589-1.2247448713915892j)
4j => (4.0, 1.5707963267948966) : 4.0*exp(j*1.5707963267948966*π) => (2.4492935982947064e-16+4j)
(2+3j) => (3.605551275463989, 0.982793723247329) : 3.605551275463989*exp(j*0.982793723247329*π) => (2+3j)
(4+1j) => (4.123105625617661, 0.24497866312686414) : 4.123105625617661*exp(j*0.24497866312686414*π) => (4+1j)
(-3-3j) => (4.242640687119285, -2.356194490192345) : 4.242640687119285*exp(j*-2.356194490192345*π) => (-2.9999999999999996-3j)
(1.4142135623730951-1j) => (1.7320508075688774, -0.6154797086703873) : 1.7320508075688774*exp(j*-0.6154797086703873*π) => (1.4142135623730951-1j)
Вложения
complex.3.py
(282 байт) 36 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 12 дек 2021, 13:50

Olej писал(а):
12 дек 2021, 13:23
Комплексная математика.
Q: Вычислите площадь параллелограмма, построенного на 2-х данных векторах z1 и z2 (исходящих из точки 0 + 0j).

A: Математически, площадь параллелограмма, построенного на 2-х векторах z1 и z2, представленных комплексными значениями — это длина (модуль) вектора, представляющего векторное произведение [ z1, z2 ]. Модуль векторного произведения вычисляется как |z1| * |z2| * sin(φ), где φ — это угол между векторами z1 и z2 (но эту же формулу можно видеть и из простой геометрической интерпретации).

Площадь параллелограмма (файл paralgrm.py):

Код: Выделить всё

#!/usr/bin/python3
import sys
from cmath import polar
from math import sin

def inpoint(prompt: str) -> complex:
   while(True):
      sys.stdout.write(prompt)
      sys.stdout.flush()
      try:
         s = sys.stdin.readline()
      except KeyboardInterrupt:  # ^C - завершение
         s = ''
         break
      if s == '':  
         break                   # ^D - завершение 
      if s == '\n':              # Enter - завершение
         break
      try:
         (x, y) = s.split()
         p = complex(float(x), float(y))
      except ValueError:
         print('ошибка ввода!')
         continue
      return p
   sys.stdout.write('\r')
   print('завершение работы')
   return None

print('координаты векторов в формате: X Y (^C,^D,Enter - завершение)')
while(True):
   z1 = inpoint('вектор №1: ')
   if(z1 == None ): break;
   z2 = inpoint('вектор №2: ')
   if(z2 == None ): break;
   n1, p1 = polar(z1)
   n2, p2 = polar(z2)
   print('площадь = {:.2f}'.format(n1 * n2 * abs(sin(p2 - p1))))   
   print( '---------------------------------' )
Выполнение:

Код: Выделить всё

$ ./paralgrm.py 
координаты векторов в формате: X Y (^C,^D,Enter - завершение)
вектор №1: 1 0
вектор №2: 0 1
площадь = 1.00
---------------------------------
вектор №1: 1 0
вектор №2: -1 0
площадь = 0.00
---------------------------------
вектор №1: 1 0
вектор №2: 0 -1
площадь = 1.00
---------------------------------
вектор №1: 1 0
вектор №2: 1 1
площадь = 1.00
---------------------------------
завершение работы
Вложения
paralgrm.py
(1.14 КБ) 73 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 12 дек 2021, 13:54

Olej писал(а):
12 дек 2021, 13:50
Комплексная математика.
Q: Напишите код вычисления периметра и площади выпуклого многоугольника (N-угольника), вершины которого заданы координатами на 2D плоскости: z1, z2, z3, … zn. Число N заранее не известно и определяется при последовательном вводе координат вершин.
Подсказка: Рассматривайте многоугольник как последовательность N-2 треугольников, последовательно отсекаемых лучами исходящими из одной (любой) вершины.

A: Площадь и периметр выпуклого многоугольника (файл polygon.py):

Код: Выделить всё

#!/usr/bin/python3
import sys
import cmath
import math

def inpoint(prompt:str) -> complex:
    while(True):
        sys.stdout.write(prompt)
        sys.stdout.flush()
        try:
            s = sys.stdin.readline()
        except KeyboardInterrupt:       # ^C - завершение работы
            print(' завершение работы')
            quit()
        if s == '':                     # ^D - завершение многоугольника
            sys.stdout.write('\r')
            return None
        try:
            (x, y) = s.split()
            p = complex(float(x), float(y))
        except ValueError:
            print('ошибка ввода!')
            continue
        return p

class polygon:
    """класс многоугольника"""
    def __init__(self, parm):
        if isinstance(parm, list):
            self.pts = parm
        else:
            self.pts = []
    def printt(self):
        msg = 'вершин {} :'.format(len(self.pts))
        for x in self.pts:
            msg += ' [{:.2f},{:.2f}]'.format(x.real, x.imag)
        print( '{}'.format(msg))
    def perimeter(self):
        summa = 0.0;
        for i in range(len(self.pts)):
            if i == 0 :
                summa += abs(self.pts[i] - self.pts[len(self.pts) - 1])
            else :
                summa += abs(self.pts[i] - self.pts[i - 1])
        return summa;
    def square( self ):
        summa = 0.0;
        for i in range(len(self.pts) - 2):
            n1, p1 = cmath.polar(self.pts[i + 1] - self.pts[0])
            n2, p2 = cmath.polar(self.pts[i + 2] - self.pts[0])
            summa += n1 * n2 * abs(math.sin(p2 - p1)) / 2.
        return summa

while(True):
    print('координаты вершин в формате: X Y (^D конец ввода)')
    parms = []
    i = 1
    while(True):
        z = inpoint('вершина № ' + str( i ) + ' : ')
        if(z == None): break;
        parms.append(z)
        i += 1
    figure = polygon(parms)
    figure.printt()
    print('периметр = {:.2f}'.format(figure.perimeter()))
    print('площадь = {:.2f}'.format(figure.square()))
    print('---------------------------------')
Проверка как это выполняется:

Код: Выделить всё

$ ./polygon.py
координаты вершин в формате: X Y (^D конец ввода)
вершина № 1 : 1 0
вершина № 2 : 0 1
вершина № 3 : -1 0
вершина № 4 : 0 -1
вершин 4 : [1.00,0.00] [0.00,1.00] [-1.00,0.00] [0.00,-1.00]
периметр = 5.66
площадь = 2.00
---------------------------------
координаты вершин в формате: X Y (^D конец ввода)
вершина № 1 : 1 1
вершина № 2 : -1 1
вершина № 3 : -1 -1
вершина № 4 : 1 -1
вершин 4 : [1.00,1.00] [-1.00,1.00] [-1.00,-1.00] [1.00,-1.00]
периметр = 8.00
площадь = 4.00
---------------------------------
координаты вершин в формате: X Y (^D конец ввода)
вершина № 1 : ^C завершение работы
Вложения
polygon.py
(2.16 КБ) 37 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 12 дек 2021, 20:17

Q: Какое кодирование использует Python 3 по умолчанию? И применяется для кодирования чего? Приведите примеры?

A: Python версий 3.х по умолчанию использует кодировку UTF-8 представления Unicode (так же как и в некоторых других современных языках, например Go). Эта кодировка используется для любых целей: для имён переменных, для хранения строчных значений, для вычисления длин строк (литер, но не байт), порядка лексографической сортировки строк, в регулярных выражениях и т. д.

Файл

Код: Выделить всё

#!/usr/bin/env python3
def make_bitseq(s: str) -> str:
   if not s.isascii():
      print("not ASCII value:")
   return s + "[" + str(len(s)) + "] : " + (" ".join(f"{ord(i):08b}" for i in s))
print(make_bitseq("bits"))
print(make_bitseq("CAPS"))
print(make_bitseq("$25.43"))
print(make_bitseq("~5"))
переменная = 'переменная'
print(make_bitseq(переменная))
Δv = "дельта Δ"
print(make_bitseq(Δv))
π = str(3.1415926)
print(make_bitseq(π))

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./coding.py 
bits[4] : 01100010 01101001 01110100 01110011
CAPS[4] : 01000011 01000001 01010000 01010011
$25.43[6] : 00100100 00110010 00110101 00101110 00110100 00110011
~5[2] : 01111110 00110101
not ASCII value:
переменная[10] : 10000111111 10000110101 10001000000 10000110101 10000111100 10000110101 10000111101 10000111101 10000110000 10001001111
not ASCII value:
дельта Δ[8] : 10000110100 10000110101 10000111011 10001001100 10001000010 10000110000 00100000 1110010100
3.1415926[9] : 00110011 00101110 00110001 00110100 00110001 00110101 00111001 00110010 00110110
Вложения
coding.py
(478 байт) 37 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 12 дек 2021, 20:22

Olej писал(а):
12 дек 2021, 20:17
Python версий 3.х по умолчанию использует кодировку UTF-8 представления Unicode (так же как и в некоторых других современных языках, например Go). Эта кодировка используется для любых целей: для имён переменных, для хранения строчных значений, для вычисления длин строк (литер, но не байт), порядка лексографической сортировки строк, в регулярных выражениях и т. д.
Отсюда следуют далеко идущие последствия:

1. В общем случае, нет необходимости указывать явно кодировку в коде

Код: Выделить всё

# -*- coding: utf-8 -*-
либо:

Код: Выделить всё

# coding: utf8
- как это было в Python 2.x

2. В некоторых операционных системах, использующих для представления Unicode кодировку отличную от UTF-8 (некоторые Windows с кодировкой UTF-16), для явного указания кодировки всё так же явно нужно указать в первых строках кодировку.

3. При вводе-выводе в файловой системе может потребоваться явно переопределить кодировку (если она должна отличаться от UTF-8).

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 13 дек 2021, 15:01

Q: С клавиатуры вводится натуральное число, к десятичной записи которого добавляется в начало и в конец цифра 1. Определить, простое ли это получившееся число.

A:

Код: Выделить всё

#!/usr/bin/python3
from math import sqrt

def simple(n:int) -> bool:
   for i in range(3, round(sqrt(n)) + 2, 2):
      if 0 == n % i : return False
   return True;

while(True):
   try:
      d1 = int(input('число: '))
      if not d1 > 0:
         print('не положительное число!')
         continue
      d2 = int('1' + str(d1) + '1')
      print('{}: {} => {sim}'.
            format(d1, d2, sim='простое' if simple(d2) else 'не простое'))
   except ValueError:
      print('ошибка: не целое число!')
      continue
   except KeyboardInterrupt:
      break
   except EOFError:
      break      
print('\rзавершение работы')
exit()
P.S. Особенностью решения является то, что проверку на делимость числа N можно производить не для всех (нечётных) делителей [3...N-1], а только до значения √N, округлённого до целого в сторону увеличения (утверждение известное из теории чисел).

Проверка выполнением:

Код: Выделить всё

$ ./simple1.py 
число: 15
15: 1151 => простое
число: 16
16: 1161 => не простое
число: 372
372: 13721 => простое
число: 373
373: 13731 => не простое
число: 3.5
ошибка: не целое число!
число: xyz
ошибка: не целое число!
завершение работы
Вложения
simple1.py
(709 байт) 32 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 14 дек 2021, 00:37

Q: Известно, что правильная рациональная дробь N / M ( N < M ) в десятичной записи может давать либо конечную запись ( 2 / 5 = 0.4 ), либо периодическую запись ( 1 / 3 = 0.(3) ). Рациональная дробь не может производить иррациональное значение (с непериодической десятичной записью, как, например, SQRT( 2 ) ). Создайте программу преобразования рациональной дроби в позиционную запись. Примите во внимание, что период может начинаться не с 1-й цифры после запятой: 1 / 12 = 0.08(3). Чтобы задача не казалась слишком лёгкой, сделайте её для произвольной системы счисления, основание которой (не только 10) вводится как отдельный параметр, например в 2-чной системе 2 / 3 = 0.(10) = 1 * ½ + 0 * ¼ + ...
Подсказка: Двигаясь поразрядно слева направо:
- остаток от деления предыдущего разряда умножаем на основание системы счисления и делим на делитель — это значение очередного разряда;
- если предыдущее деление происходит нацело, то это конечная, непериодическая дробь, и процесс закончен;
- если же остаток не нулевой, то сравниваем его с остатками на всех предыдущих шагах, и если равный остаток обнаружился, то это и есть период;
- если же равный остаток не найден, то переходим к младшему разряду и весь цикл повторяем заново...

А чтобы задача не казалась слишком простой, в качестве дополнительного упражнения добавим:
1. Чтобы результат преобразования мог быть задан в любой системе счисления (не только 2, 8, 16... но и в любой произвольной, например, 7-чной, 15-ричной, 17-ричной... :lol: )
2. Числитель дроби может быть больше знаменателя, тогда целую часть результата нужно тоже выразить в той же системе счисления.

A: Решение:

Код: Выделить всё

#!/usr/bin/env python3
import string

alpha = string.digits + string.ascii_uppercase
while True:
   try:
      metr = int(input("система счисления: "))
      ch   = int(input("числитель: "))
      zn   = int(input("знаменатель: "))
   except ValueError:
      print("ошибка: не целое число!")
      continue
   except KeyboardInterrupt:
      break
   except EOFError:
      break      
   ceil = ch // zn if ch > zn else 0
   if 0 == ceil: sceil = "0"  
   else:
      sceil = ""
      while ceil > 0:
         sceil += alpha[ceil % metr]
         ceil //= metr
      sceil = sceil[::-1]     # реверс
   sceil += "."               # отображение целой части
   ost = ch - int(ceil * zn)  # остаток (деления) дробной части
   simb = ""                  # отображение дробной части
   list = []
   peri = 0 
   while True: 
       ost *= metr
       simb += alpha[ost//zn]
       ost %= zn;
       if 0 == ost:           # это конечная дробь
          print("{}/{} = {}".format(ch, zn, sceil+simb))         
          break
       if ost in list:       # найден совпадающий остаток 
          simb = simb[:-1]
          print("{}/{} = {}".format(ch, zn,
                 sceil+"("+simb+") длина периода " + str(peri)))
          break
       else: 
          list.append(ost)
       peri += 1       
print("\r")
Проверяем:

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./period.py
система счисления: 16
числитель: 53
знаменатель: 59
53/59 = 0.(E5F75270D0456C797DD49C34115B1) длина периода 29
система счисления: 8
числитель: 53
знаменатель: 59
53/59 = 0.(7137352234150105330745756511606404255436276724470320212661) длина периода 58
система счисления: 2
числитель: 53
знаменатель: 59
53/59 = 0.(1110010111110111010100100111000011010000010001010110110001) длина периода 58
система счисления: 10
числитель: 11
знаменатель: 13
11/13 = 0.(846153) длина периода 6
система счисления: 10
числитель: 283
знаменатель: 293
283/293 = 0.96587030716723549488054607508532423208191126279863481228668941979522184300341296928327645051194539249146757679180887372013651877133105802047781569) длина периода 146
система счисления: 16
числитель: 1
знаменатель: 8
1/8 = 0.2
система счисления: 8
числитель: 1
знаменатель: 8
1/8 = 0.1
система счисления: ^C
Вложения
period.py
(1.46 КБ) 37 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 14 дек 2021, 18:29

Q: Возведение в степень. Что может быть проще? Простое возведение вещественного числа X в степень N – это N – 1 умножений в цикле, это элементарно... Но умножение – это дорогая, вычислительно трудоёмкая операция…
Формулировка данной задачи такая:
• написать функцию возведение в степень XN (N — натуральное число), но так, чтобы для этого требовалось минимальное число операций умножения;
• постарайтесь контролировать и включить в вывод число потребовавшихся для вычисления операций умножения (что соответствует времени выполнения при достаточно большим N).

A: Возведение вещественного числа в целочисленную степень. Логика такого решения принадлежит Чарльзу Энтони Хоару (Charles Anthony Richard Hoare) и состоит в том, что возведение делается в половинную степень, а потом результаты перемножаются:

Код: Выделить всё

#!/usr/bin/env python3

def power(a:float, n:int) -> (float, int):
   if n == 1 : return (a, 0)
   (a2, m) = power(a, n // 2)
   a2 = a2 * a2
   m += 1 
   if n % 2 != 0:
      a2 *= a
      m += 1
   return a2, m

while(True):
   try:
      e = float(input("что возводить? : "))
      n = int(input("в какую степень? : "))
      r = power(e, n)
      print("{}^{} = {:.5e}, число умножений {}".
            format(e, n, r[0], r[1]))
   except ValueError:
      print("ошибочный формат ввода!")
      continue
   except KeyboardInterrupt:
      break
   except EOFError:
      break      
print('\rзавершение работы')
Это отличный пример, иллюстрирующий, что даже общеизвестные тривиальные вещи, с точки зрения вычислительных методов, оптимально оказывается реализовывать по-другому:

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./powerm.py 
что возводить? : 2
в какую степень? : 100
2.0^100 = 1.26765e+30, число умножений 8
что возводить? : 3
в какую степень? : 51
3.0^51 = 2.15369e+24, число умножений 8
что возводить? : 5 
в какую степень? : 150
5.0^150 = 7.00649e+104, число умножений 10
что возводить? : 9
в какую степень? : 301
9.0^301 = 1.68653e+287, число умножений 12
завершение работы^C
Вложения
powerm.py
(694 байт) 46 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 15 дек 2021, 23:18

Классика: Ханойская башня!
Утверждается, что эту задачу сформулировали и решают до сих пор монахи каких-то из монастырей Тибета. Задача состоит в том, чтобы пирамидку из колец (на манер детской игрушки), нанизанную на один из 3-х стержней, перенести на другой такой же стержень, придерживаясь строгих правил:
• пирамидка состоит из N колец разного размера, уложенных по убыванию диаметра колец один на другой;
• перекладывать за одну операцию можно только одно кольцо с любого штыря на любой …
• но только при условии, что класть можно только меньшее кольцо сверху на большее, но никак не наоборот;
• нужно, в итоге, всю исходную пирамидку, лежащую на штыре №1, переместить на штырь №3, используя штырь №2 как промежуточный.
Например, для 2-х колец результат получается такой вот последовательностью перекладываний: 1 => 2 , 1 => 3 , 2 => 3
hanoj.jpg
hanoj.jpg (32.03 КБ) 1169 просмотров
По преданию, эту задачу по перекладыванию N=10 колечек, решают тибетские монахи, и когда они её, наконец, решат, тогда и наступит конец света … Армагедон, в нашей западной нотации.

A: Ханойская башня:

Код: Выделить всё

#!/usr/bin/env python3
import sys

line = 10                         # длина строки вывода
pos = 0
   
def put(fr:int, to:int):          # операция переноса fr=>to
   global pos
   if pos != line - 1:
      print("{} => {}".format(fr, to), end=" | ")
   else:
      print("{} => {}".format(fr, to))
   pos = (pos + 1) % line
   return

def temp(fr:int, to:int) -> int:  # выбор промежуточной позиции 
   for i in range(1, 3): 
      if i not in (fr, to):
         break
   return i

def move(fr:int, to:int, n:int) -> int:
   if(1 == n):
      put(fr, to)
      m = 1
   else:
      m = move(fr, temp(fr, to), n - 1)
      put(fr, to)
      m += (move(temp(fr, to), to, n - 1) + 1)
   return m

try:
   if len(sys.argv) > 1: n = int(sys.argv[1])
   else: n = int(input("число колец?: "))
except ValueError:
   print("ошибочное значение!")
   exit()
print("размер пирамиды: n=", n)
n = move(1, 3, n)                 # вот и всё решение!!!
if pos != 0: print() 
print("общее число перемещений:", n)
Выполнение:

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./hanoj.py 5
размер пирамиды: n= 5
1 => 2 | 1 => 2 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1
2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 3 | 2 => 1 | 2 => 2 | 1 => 2 | 2 => 1
2 => 2 | 2 => 1 | 2 => 1 | 2 => 3 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 3 | 2 => 1 | 2 => 3
1 => 3 |
общее число перемещений: 31

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./hanoj.py 7
размер пирамиды: n= 7
1 => 2 | 1 => 2 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1
2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 1 => 2 | 2 => 1
2 => 2 | 2 => 1 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2
1 => 2 | 1 => 2 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1
2 => 1 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2
2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 2
1 => 2 | 1 => 2 | 2 => 2 | 1 => 3 | 2 => 1 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 2 => 1
2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 1 => 2 | 2 => 1
2 => 2 | 2 => 1 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 2
1 => 2 | 2 => 1 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 3 | 1 => 2 | 1 => 2 | 2 => 2 | 1 => 2
2 => 1 | 2 => 2 | 1 => 2 | 1 => 2 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 2 | 1 => 2 | 1 => 2
2 => 2 | 1 => 3 | 2 => 1 | 2 => 2 | 1 => 2 | 2 => 1 | 2 => 2 | 2 => 1 | 2 => 1 | 2 => 3
1 => 2 | 1 => 2 | 2 => 2 | 1 => 3 | 2 => 1 | 2 => 3 | 1 => 3 |
общее число перемещений: 127
Это особый образец плодотворности рекурсии! Попробуйте записать решение этой задачи в не рекурсивной форме. А ещё лучше — попробуйте затем кому-то объяснить ваше решение в не рекурсивной форме.
Примечание: О том, насколько это непростое занятие, не рекурсивное решение этой задачи, и как придётся поуродоваться :lol: - вы можете почитать вот в этой очень интересной статье: В лабиринтах Ханойских башен и по ссылкам оттуда на публикации … как изощряются профессионалы. Там же утверждается, что общее число операций равно 2^N-1, где N количество дисков – что и подтверждает наше выполнение.
Вложения
hanoj.py
(1.1 КБ) 36 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Осваиваем Python по-быстрому №2

Непрочитанное сообщение Olej » 17 дек 2021, 01:22

Q: Решето Эратосфена — классический алгоритм (известный ещё в Древней Греции) нахождения всех простых чисел (отсеивания составных) не превышающих заданное n. Вот одно из описаний алгоритма (по ссылке):
Для нахождения всех простых чисел не больше заданного числа n, следуя методу Эратосфена, нужно выполнить следующие шаги:
1. Выписать подряд все целые числа от двух до n (2, 3, 4, …, n).
2. Пусть переменная p изначально равна 2 — первому простому числу.
3. Зачеркнуть в списке числа от 2*p до n считая шагами по p (это будут числа кратные p: 2*p, 3*p, 4*p, …).
4. Найти первое не зачёркнутое число в списке, большее чем p, и присвоить значению переменной p это число.
5. Повторять шаги 3 и 4, пока возможно (пока p не достигнет n).
Реализуйте этот алгоритм в его классическом изложении.

A: Алгоритм Эратосфена (отбор простых чисел) в его классическом изложении:

Код: Выделить всё

#!/usr/bin/python3

def aristofn(n:int) -> list:
   a = [i for i in range(2, n, 1)]
   i = 0
   while True:
      try:
         p = a[i]
      except IndexError:
         break 
      for j in range(2 * p, n, p):
         if j in a: a.remove(j)
      i += 1
   print('шагов просеивания: ', i + 1)  
   return a

while(True):
   try:
      d = int(input('число: ')) 
   except ValueError:
      print('ошибка: не целое положительное число!')
      continue
   except (KeyboardInterrupt, # ^C
           EOFError):         # ^D - EOF
      print('\rзавершение работы')
      exit()
   else:
      print(d, ":", *aristofn(d))
Выполнение:

Код: Выделить всё

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./aristofc.py 
число: 55
шагов просеивания:  17
55 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
число: 100
шагов просеивания:  26
100 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
число: 300
шагов просеивания:  63
300 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293
завершение работы
Вложения
aristofc.py
(691 байт) 74 скачивания

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 6 гостей