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

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

Модератор: Olej

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

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

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

Olej писал(а):
17 дек 2021, 01:22
A: Алгоритм Эратосфена (отбор простых чисел) в его классическом изложении:
Q: Алгоритм Эратосфена в его классическом изложении достаточно трудоёмкий (чрезмерно большое число сравнений). Для его оптимизации можно предпринять:
1. Начальный ряд можно выписать только для нечётных чисел, дополнив его в начале цифрой 2 как единственно чётным простым: (2, 3, 5, 7, …, n).
2. На шаге № 3 числа можно зачеркивать начиная сразу с числа p2, потому что все составные числа меньше него уже будут зачеркнуты к этому времени.
3. И, соответственно, останавливать алгоритм можно, когда p2 станет больше, чем n.
4. Также, все p большие чем 2 — нечётные числа, и поэтому для них можно считать шагами по 2*p (а не p), начиная с p2.
Реализуйте оптимизированный алгоритм.

A: Оптимизированный алгоритм Эратосфена, позволяющий уменьшить число «отсеиваний» на несколько порядков:

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

#!/usr/bin/python3

def aristofn(n:int) -> list:
   a = [2]
   a.extend([i for i in range(3, n, 2)])
   i = 1
   while True:
      try:
         p = a[i]
         if p * p > n:
            break
      except IndexError:
         break
      for j in range(p * p, n, 2 * p):
         if j in a: a.remove(j)
      i += 1
   print('шагов просеивания: ', i)  
   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$ ./aristofn.py 
число: 55
шагов просеивания:  4
55 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
число: 100
шагов просеивания:  4
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
шагов просеивания:  7
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
завершение работы
P.S. И здесь и в предыдущем решении показано число "шагов просеивания" которые отличаются (для вариантов) в разы, но это число "пробегов" по ряду, или число найденных простых чисел для которых делается просеивание. Но в каждом таком просеивании и число сравнений/вычёркиваний будет отличаться в несколько раз. Тогда общее сравнение производительности (произведение 2-х факторов) будет уже существенно больше.
Вложения
aristofn.py
(748 байт) 35 скачиваний

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

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

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

Olej писал(а):
12 дек 2021, 13:54
A: Площадь и периметр выпуклого многоугольника (файл polygon.py):
Более упорядоченный вариант (в смысле ввода исходных данных) предыдущей задачи:

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

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

def inpoint(prompt:str) -> complex:
   while(True):
      try:
         ls = input(prompt).split()
         if 0 == len(ls):             # Enter - завершение многоугольника
            return None
         if len(ls) != 2:
            raise ValueError 
         return complex(float(ls[0]), float(ls[1]))
      except KeyboardInterrupt:       # ^C - завершение работы
         print('\rзавершение работы')
         quit()
      except ValueError:
         print('ошибка ввода!')
         continue

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 (Enter конец ввода)')
   parms = []
   while(True):
      z = inpoint('вершина №' + str(len(parms) + 1) + '? : ')
      if(z == None): 
         print('.................................')
         break;
      parms.append(z)
   figure = polygon(parms)
   figure.printt()
   print('периметр = {:.2f}'.format(figure.perimeter()))
   print('площадь = {:.2f}'.format(figure.square()))
   print('---------------------------------')

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

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./polygon.py 
координаты вершин в формате: X Y (Enter конец ввода)
вершина №1? : 1
ошибка ввода!
вершина №1? : 1 2 3
ошибка ввода!
вершина №1? : 1.0 2
вершина №2? : 1.5 3.3
вершина №3? : 0 0
вершина №4? : 
.................................
вершин 3 : [1.00,2.00] [1.50,3.30] [0.00,0.00]
периметр = 7.25
площадь = 0.15
---------------------------------
координаты вершин в формате: X Y (Enter конец ввода)
завершение работы

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

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./polygon.py 
координаты вершин в формате: X Y (Enter конец ввода)
вершина №1? : 1.1.1 2
ошибка ввода!
вершина №1? : 1 2.d
ошибка ввода!
завершение работы
Вложения
polygon.py
(2.02 КБ) 36 скачиваний

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

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

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

Olej писал(а):
17 дек 2021, 01:27
P.S. И здесь и в предыдущем решении показано число "шагов просеивания" которые отличаются (для вариантов) в разы, но это число "пробегов" по ряду, или число найденных простых чисел для которых делается просеивание. Но в каждом таком просеивании и число сравнений/вычёркиваний будет отличаться в несколько раз. Тогда общее сравнение производительности (произведение 2-х факторов) будет уже существенно больше.
Возвращаясь к этим 2-м ранее реализациям...

Q: Реализуйте функции вычисления простых чисел в 2-х предыдущих задачах так, чтобы они могли возвратить и число циклов просеивания и общее число операций просеивания. Сравните результаты реализаций задач.

Фишка такой задачи в том, что она иллюстрирует ту особенность, что return в функции Python может возвращать одновременно сколько угодно разнообразных и сложно структурированных данных.

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

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

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

Olej писал(а):
18 дек 2021, 13:10
Q: Реализуйте функции вычисления простых чисел в 2-х предыдущих задачах так, чтобы они могли возвратить и число циклов просеивания и общее число операций просеивания. Сравните результаты реализаций задач.
1-я из задач:

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

#!/usr/bin/python3

def aristofn(n:int) -> (tuple, list):
   a = [i for i in range(2, n, 1)]
   i = 0; k = 0
   while True:
      try:
         p = a[i]
      except IndexError:
         break 
      for j in range(2 * p, n, p):
         k += 1
         if j in a: a.remove(j)
      i += 1
   return (i + 1, k), a

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

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

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

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

Olej писал(а):
18 дек 2021, 13:13
Q: Реализуйте функции вычисления простых чисел в 2-х предыдущих задачах так, чтобы они могли возвратить и число циклов просеивания и общее число операций просеивания. Сравните результаты реализаций задач.
2-я из задач:

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

#!/usr/bin/python3

def aristofn(n:int) -> (tuple, list):
   a = [2]
   a.extend([i for i in range(3, n, 2)])
   i = 1; k = 0
   while True:
      try:
         p = a[i]
         if p * p > n:
            break
      except IndexError:
         break
      for j in range(p * p, n, 2 * p):
         k += 1
         if j in a: a.remove(j)
      i += 1
   return (i, k), a   

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

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

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

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

Olej писал(а):
18 дек 2021, 13:13
1-я из задач:
Olej писал(а):
18 дек 2021, 13:14
2-я из задач:
Сравнительное выполнение:

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

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./aristofc.py
число: 55
просеивание: циклов 17 шагов 68
55 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
число: 100
просеивание: циклов 26 шагов 144
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 шагов 513
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
число: 1000
просеивание: циклов 169 шагов 1956
1000 : 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 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
завершение работы

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

olej@R420:~/2021/own.BOOKs/tasks-Python/DRAFT$ ./aristofn.py
число: 55
просеивание: циклов 4 шагов 12
55 : 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
число: 100
просеивание: циклов 4 шагов 28
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
просеивание: циклов 7 шагов 111
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
число: 1000
просеивание: циклов 11 шагов 457
1000 : 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 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
завершение работы
Хорошо видно, что общее число (немалое) операций (просеиваний) в вариантах отличается в 5 раз.

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

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

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

Q: В колонии на осваиваемой планете решили выбрать органы управления. Каждый из его жителей организовал партию, которую сам и возглавил. Отметим, что, ко всеобщему удивлению, даже в самой малочисленной партии оказалось не менее двух человек. К сожалению, финансовые трудности не позволили создать парламент, куда вошли бы, как предполагалось по правилам, президенты всех партий. Посовещавшись, колонисты решили, что будет достаточно, если в парламенте будет хотя бы один член каждой партии. Помогите организовать такой, как можно более малочисленный, парламент, в котором будут представлены члены всех партий.
Каждая партия и, соответственно, её президент имеют одинаковый порядковый номер от 1 до N (4⩽N⩽150). Вам даны списки всех N партий планеты. Выведите предлагаемый вами парламент в виде списка номеров его членов.

P.S. Эта задача предполагает достаточно объёмный ввод исходных данных. Поэтому организуйте ввод так, чтобы он мог производиться как непосредственно с терминала, так и перенаправлением потока из файла.

A: Формирование парламента минимального размера.
Вариант решения:
- каждая партия представлена строкой номеров участников (список);
- на каждом шаге ищем номер участника, который наиболее часто встречается во всех строках;
- включаем этот номер в искомый результат;
- удаляем все строки (списки), куда входил выбранный номер;
- повторяем всё это последовательно до тех пор, пока у нас не останется необработанных строк;
Код:

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

#!/usr/bin/env python3
import os
import sys

def inline() -> list:
   prompt = "список целых: " if term else ""   
   sys.stdout.write(prompt)
   sys.stdout.flush()
   s = sys.stdin.readline()
   if s == "\n" or s == "":        # Enter | ^D - завершение ввода
      sys.stdout.write("\r" + " " * len(prompt) + "\r")
      return None
   lst = s.split()
   for i in range(len(lst)):
      try:
         lst[i] = int(lst[i]) 
      except ValueError:
         return []
   if not term: print(*lst)
   return lst

term = os.isatty(sys.__stdin__.fileno())
if not term: print("исходные:")
full = []                          # исходный список списков
while True:                        # ввод данных
   line = inline()
   if line == None: break;
   if 0 == len(line):
      print("\rошибка ввода!")
   else:
      full.append(line)

result = []                        # результирующий список
while len(full) != 0:              # фильтрация списка
   counter = {}                    # dict вхождений
   for line in full:
      for d in line:
         try:
            counter[d] += 1
         except KeyError:
            counter[d] = 1
   sorted_tuple = sorted(counter.items(), key=lambda x: x[1], reverse=True)
   erase = sorted_tuple[0][0]
   result.append(erase)
   for j in range(len(full) - 1, -1, -1):
      if erase in full[j]:
         full.pop(j)

print("результат: ", *result)
Проверяем как это работает:

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

$ ./partija.py
список целых: 1 3 5 7
список целых: 2 4 6 8
список целых: 5 6
список целых: 8 1
список целых: 
результат:  1 6
То же самое перенаправлением входного потока из файла:

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

$ ./partija.py < p1.in
исходные:
1 2
2 4 6 7
3 6 7
4 5 7
5 6
6 4
7 5
результат:  6 5 1

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

$ ./partija.py < p2.in
исходные:
2 4 7
4 6 7 5
3 6 7
4 5 7 1
5 6 2 3
6 4 7 1
7 5 2
результат:  7 5
Вложения
partija.py
(1.48 КБ) 35 скачиваний

Ответить

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

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

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