Algorithms and Data Structures
Algorithms and Data Structures
1 Линейный поиск
Будем работать с текстовым файлом, в каждой строке одно слово, за основу
можно взять список слов русского языка – скачать тут (преобразуйте в подходящую
для вашей системы кодировку): [Link] Содержимое
файла выглядит примерно так:
2
Данные берём из текстового файла и организуем простой цикл:
word = input("Введите слово для поиска - ")
f = open("[Link]", 'r')
lines = [Link]().split('\n')
[Link]()
for i in range(len(lines)):
if lines[i] == word:
print(i, lines[i])
break
Когда решение найдено, досрочно выходим из цикла.
Оцените минимальное, максимальное и среднее количество шагов поиска
по данному алгоритму.
2 Бинарный поиск
Очевидно, что следует отказаться от последовательного перебора при
поиске. Ускорить алгоритм поиска можно, например, делением диапазона
пополам и определением в какой из половинок располагается искомое слово.
Таким образом на каждом шаге оставшаяся часть диапазона поиска сокращается в
2 раза. Можно дать оценку средней величине временных затрат как log2n, то есть с
ростом мощности исследуемого множества n, затраты на реализацию алгоритма
растут незначительно – логарифмически. Это заметно ниже чем квадратичный рост
(n2 - в простейших алгоритмах сортировки) или линейный рост (n - в линейном
поиске).
word = input("Введите слово для поиска - ")
f = open("[Link]", 'r')
lines = [Link]().split('\n')
[Link]()
mn = 0
mx = len(lines) - 1
pos = (mx + mn) // 2
i = 1
while word != lines[pos]:
if word < lines[pos]:
mx = pos - 1
if word > lines[pos]:
mn = pos + 1
pos = (mx + mn) // 2
3
i += 1
print(i, lines[pos])
def func(x):
return sin(x)
def to_rad(g):
return g * pi / 180
mn = 0
mx = 180
st = 15
for g in range(mn, mx + 1, st):
# print(g, round(func(to_rad(g)), 3))
# print(g, str(func(to_rad(g)))[:5] )
print("{0:3} - {1:.3f}".format(g, func(to_rad(g))))
Результат работы:
0 - 0.000
15 - 0.259
30 - 0.500
45 - 0.707
60 - 0.866
75 - 0.966
90 - 1.000
105 - 0.966
120 - 0.866
135 - 0.707
150 - 0.500
165 - 0.259
180 - 0.000
def to_rad(g):
return g * pi / 180
mn = 0
mx = 135
q = 0.01
l, r = mn, mx
while (r - l > q):
ml = l + (r - l) / 3
mr = r - (r - l) / 3
if (func(to_rad(ml)) < func(to_rad(mr))):
l = ml
else:
r = mr
result = (l + r) / 2
print("Оптимум функции тут - {0:.3f}".format(func(to_rad(result))))
Задание 1.
Допишите программу так, чтобы подсчитать количество шагов до
нахождения оптимума в данном примере. Сравните эффективность
методов.
5
2. РЕКУРСИЯ
2.1. Факториал
2.2. Числа Фибоначчи
2.3. Ханойская башня
2.1. Факториал
number = int(input())
print(for_factorial(number))
def for_factorial(n):
...
return result
def rec_factorial(n):
if n == 1:
return 1
else:
return rec_factorial(n - 1) * n
number = int(input())
print(for_factorial(number))
print(rec_factorial(number))
6
вызов, а можно сразу вернуть ответ - это 1.
Шаг рекурсии – эта та часть функции, где происходить её рекурсивный вызов
– функция вызывает сама себя. Если при рекурсивном вызове не будет меняться
значение аргумента функции, то она «зациклится» - будет стоять на месте до тех
пор, пока не переполнится стек вызовов функции (для Питона это 1000).
Как точек останова, так и шагов рекурсии может быть несколько. При
отсутствии точки останова, рекурсивная функция будет вызывать сама себя до тех
пор, пока не переполнится стек вызовов функции.
Задание 3.
Напишите рекурсивную функцию перевода из десятичного числа в
двоичное.
Задание 4.
Напишите рекурсивную функцию перевода из двоичного числа в
десятичное.
7
2.2. Числа Фибоначчи
порядковый
1 2 3 4 5 6 7 8 9 10
номер
значение
1 1 2 3 5 8 13 21 34 55
числа
или словами: первое и второе число равны единице, а каждое последующее есть
сумма двух предшествующих. Формально это можно выразить так:
Число 1 = 1
Число 2 = 1
Число N = Число(N-1) + Число(N-2)
Напишем соответствующую программу, в основе которой лежит рекурсивная
функция fib:
def fib(n):
if n < 3:
return 1
else:
return fib(n-1) + fib(n-2)
10
tab[1] = 1
tab[2] = 1
print(fib(n))
11
2.3. Ханойская башня
Одна легенда гласит, что в Великом храме города Бенарес, под собором,
отмечающим середину мира, находится бронзовый диск, на котором укреплены 3
алмазных стержня, высотой в один
локоть и толщиной с пчелу. Давным-
давно, в самом начале времён, монахи
этого монастыря провинились перед
богом Брахмой. Разгневанный Брахма
воздвиг три высоких стержня и на один
из них возложил 64 диска, сделанных из
чистого золота. Причём так, что каждый меньший диск лежит на большем.
Как только все 64 диска будут переложены со стержня, на который Брахма
сложил их при создании мира, на другой стержень, башня вместе с храмом
обратятся в пыль и под громовые раскаты погибнет мир.
Количество перекладываний в зависимости от количества колец вычисляется
по формуле 2n-1.
Число перемещений дисков, которые должны совершить монахи, равно 18
446 744 073 709 551 615. Если бы монахи, работая день и ночь, делали каждую
секунду одно перемещение диска, их работа продолжалась бы почти 585
миллиардов лет.
Эту легенду как и саму игру придумал французский
математик Эдуард Люка в 1883 году, её продавали как забавную
игрушку. Первоначально она называлась «Профессор Клаус
(Claus) из Колледжа Ли-Су-Стьян (Li-Sou-Stian)», но вскоре
обнаружилось, что таинственный профессор из несуществующего
колледжа - не более чем анаграмма фамилии изобретателя игры,
профессора Люка (Lucas) из колледжа Сен-Луи (Saint Louis).
12
Опишем рекурсивную функцию в обобщённом виде:
шаг 0: исходное состояние
В программе сначала
устанавливаем количество
колец на первом стрежне n,
затем запускаем рекурсивную
функцию для n колец.
В рекурсивной функции
проверяем не наступила ли уже
точка останова и, если нет, то
исполняем три описанных ранее
шага, два из которых являются Алгоритм программы. Алгоритм рекурсивной
рекурсивными вызовами. функции Tower.
Код Результат
def Tower(n, a, b, c): Код функции
from 1 to 2
if n>0: from 1 to 3
Tower(n-1, a, c, b) from 2 to 3
print('from', a, 'to', b) from 1 to 2
from 3 to 1
Tower(n-1,c,b,a)
from 3 to 2
from 1 to 2
n = 3 Код программы
Tower(n,1,2,3)
13
Можно немного усложнить себе задачу и сделать пошаговый показ того, как
кольца от шага к шагу мигрируют между стержнями:
Код Результат
def printTower(x,y): start Tower => 3 0 0
global lst from 1 to 2 => 2 1 0
lst[x-1] -= 1 from 1 to 3 => 1 1 1
lst[y-1] += 1 from 2 to 3 => 1 0 2
print(*lst)
from 1 to 2 => 0 1 2
from 3 to 1 => 1 1 1
def Tower(n, a, b, c):
from 3 to 2 => 1 2 0
if n>0:
Tower(n-1, a, c, b) from 1 to 2 => 0 3 0
print('from', a, 'to', b, '=>', end='')
printTower(a,b)
Tower(n-1,c,b,a)
n = 3
lst = [n,0,0] # количество колец на стержнях
print('start Tower =>', *lst)
Tower(n,1,2,3)
14
3. КОМБИНАТОРИКА
15
Решающие алгоритмы:
Перебор подмножеств (бинарные маски)
Порождение перестановок (рекурсия)
Поиск решения методом динамического программирования.
def getSubsets(k):
global tmp
if k == len(lst):
print(*tmp)
else:
[Link](lst[k])
getSubsets(k+1)
[Link]()
getSubsets(k+1)
def getSubsetsBin():
n = len(lst); count = 2**n
for variant in range(count):
tmp = []
for pos in range(n):
if (1 << pos) & variant:
[Link](lst[pos])
print(variant, '\t', *tmp)
def getPermutations():
if len(tmp) == len(lst):
print(*tmp)
16
else:
for i in range(len(lst)):
if not choice[i]:
choice[i] = True
[Link](lst[i])
getPermutations()
choice[i] = False
[Link]()
17
4. Поиск в тексте
1. Наивный алгоритм.
Это простейший поиск, который предполагает последовательное
сравнение шаблона поиска с символами основного текста, начиная с
самой левой позиции и, в худшем случае, завершая позицией, равной
длина текста минус длина шаблона поиска.
Допустим, что нужно в тексте "Раму мыла мама" найти подстроку
"мама".
Для наглядности представим шаги поиска наивным алгоритмом
в виде последовательных строк таблицы:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 Р а м у м ы л а м а м а
1 м а м а
2 м а м а
3 м а м а
4 м а м а
...
10 м а м а
11 м а м а
18
падении хотя бы одного символа сдвигаем строку поиска на один сим-
вол вправо и снова производим посимвольное сравнение слева-
направо по всей длине строки поиска.
haystack = "Раму мыла мама"
needle = "мама"
haystack = [Link]()
needle = [Link]()
'''
Наивный алгоритм:
двойной цикл и сравнение символов слева-направо
'''
result = "Строка не найдена"
for pos in range(len(haystack)-len(needle)):
for i in range(len(needle)):
if needle[i] != haystack[pos+i]:
break
if i == len(needle)-1:
result = pos
break
print(result)
Эффективность такого алгоритма невысока, так как при большом
количестве частичных совпадений оценка мощности поиска будет
приближаться к O(len(haystack)·len(needle)), а при малом числе частич-
ных совпадений (когда внутренний цикл выполняется только один раз)
оценка снижается до len(haystack)-len(needle).
2. Алгоритм Бойера-Мура.
При рассмотрении наивного алгоритма было показано, что про-
исходит множество заведомо излишних проверок. Преимущество ал-
горитма Бойера-Мура в том, что часть проверок пропускаются как за-
ведомо не дающие результата. Это достигается ценой некоторого ко-
личества предварительных вычислений над шаблоном поиска, после
чего шаблон можно сравнивать с исходным текстом не во всех пози-
циях. Рассмотрим пример: текст "Большой корабль" и подстрока для
поиска в нём "кора". При первом же сравнении мы понимаем, что под-
строка не совпадает с тестом, далее перед нами стоит выбор как далеко
вправо сдвинуть шаблон поиска на один символ или больше. Так вот,
посмотрим на позицию в основной строке напротив последнего сим-
вола в шаблоне поиска - это символ "ь". Внимание вопрос: а есть ли
этот символ в шаблоне поиска? Конечно нет! А значит нет смысла пе-
репроверять все позиции и можно сдвинут шаблон сразу на следующий
19
после "ь" символ. Там также повторяется ситуации отсутствия символа
" " в шаблоне поиска и на третьем шагу поиска мы уже находим пози-
цию искомой подстроки в строке:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 Б о л ь ш о й к о р а б л ь
1 к о р а
2 к о р а
3 к о р а
20
вол "о" встречается в шаблоне, поэтому сдвигаем так, чтобы совме-
стить "о" из шаблона с "о" в тексте, то есть на расстояние символа "о"
от правого края шаблона.
Итак, основная идея алгоритма состоит в том, чтобы сдвигать
подстроку поиска настолько далеко вправо за один шаг насколько это
возможно, чтобы не пропустить позицию ответа. Важная особенность
состоит в том, что, если символ, стоящий в основном тексте напротив
последнего символа шаблона встречается в шаблоне не один раз, то
сдвигаем шаблон вправо на расстояние от правой границы шаблона до
этого символа (исключая самый правый).
Проанализируйте шаги поиска подстроки в тексте по примеру,
приведенному в следующей таблице:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 Р а м у м ы л а м а м а
1 м а м а
2 м а м а
3 м а м а
4 м а м а
haystack = [Link]()
needle = [Link]()
21
# шаг 1 - составим словарь пар (символ, сдвиг)
d = {} # объявили словарь
setText = set(haystack) # сбросили во множество, чтобы сократить перебор
for char in setText: # тут перебор по множеству символов
d[char] = len(needle) # инициализируем значениями, равными длине needle
22
23
5. Область оптимальных решений.
Задания для самостоятельного исполнения.
Техническое задание.
Разработать программу со следующим функционалом:
1) разработать класс Smartphone для хранения данных об
объектах, объекты – это телефоны;
2) считать данные из файла [Link] и поместить их в список
объектов;
3) отсортировать список по убыванию по производительности
смартфонов (поле power) и вывести три лучших;
4) отсортировать список по убыванию по продолжительности
работы (поле time) и вывести три лучших;
5) выбрать объекты, которые находятся в области Pareto (см.
рисунок) и вывести данные о них в текстовый файл [Link].
Выводить данные в том же формате, как они были во входном
файле.
Сортировка:
пузырьковая
выбором
вставкой
пирамидальная
быстрая (рекурсивный метод)
перечислением
25
7. Объекты и сортировка.
Задания для самостоятельного исполнения.
Вспомогательные материалы
смотрите в Презентациях Лекций…
тут пробел
тут табуляция
27
8. Динамическое программирование.
def factorial(n) {
if n == 1:
return 1
else:
return factorial(n-1) * n
n = 5
print(factorial(n))
28
Минимальная цена пути
Входные данные
В первой строке ввода задано два числа N и M - размеры таблицы (1 ≤ N ≤ 20,
1 ≤ M ≤ 20).
В последующих N строках по M чисел в каждой - стоимость соответствую-
щих клеток таблицы (целые числа от 0 до 100).
Выходные данные
Выведите одно целое число - это количество монет за минимальную стои-
мость прохода от входа до выхода из таблицы.
Примеры
№ INPUT OUTPUT
1 3 4 8
1 1 1 1
5 2 2 10
9 4 2 1
2 5 5 11
1 1 1 1 1
3 100 100 100 100
1 1 1 1 1
2 2 2 2 1
1 1 1 1 1
Если решать задачу поиска пути "наивным" методом полного перебора, то
мы встретимся с "проклятием размерности" - на каждом шаге выбор делается
между двумя возможными траекториями, таким образом порождается бинарное де-
рево решений. Например, в таблице со сравнительно небольшой размерностью
21Х21 чтобы дойти от левого верхнего угла только до середины таблицы (второ-
степенная диагональ) нужно будет перебрать 2^20 путей, то есть более миллиона
вариантов – попробуйте сами нарисовать небольшую таблицу, например, размером
4Х4 и подсчитать общее количество возможных путей от угла до диагонали.
29
Рассмотренный алгоритм не подходит для оперативного принятия решения,
например, в играх. Представьте, что вам нужно в динамичной сцене 2D-игры вы-
числять оптимальные пути для 10 бойцов на сравнительно небольшом поле 100 на
100 (сами оцените порядок вычислений).
К примеру, для данной карты общее количество возможных вариантов путей
(из угла в угол) около 140 миллиардов:
* * * * *
30
Далее приведено пошаговое решение задачи поиска минимальной длины
пути. Обратите внимание, что итоговая таблица «потребляет» данные из исходной
– в исходной приведены «стоимости» каждой отдельной ячейки, а в итоговой «сто-
имость» прохода по минимальному пути до каждой ячейки:
Исходная таблица: Длины путей по границам:
1 1 1 1 1 2 3 4
5 2 2 10 6
9 4 2 1 15
6 4 6 4 5 14
15 15 8 7 8
tab = []
for i in range(n): # ввод исходной таблицы
[Link](list(map(int, input().split()[:m])))
31
При решении данной задачи "динамикой" мы, приходя в некоторую текущую
ячейку, "забывали" все возможные траектории до нее, выбирая только минималь-
ный путь, тем самым сокращая дальнейшее количество переборов - за счёт этого
и достигалась существенная экономия времени поиска решения. Но что, если
нужно будет найти не один самый короткий путь, а общее количество возможных
путей при некоторых заданных ограничениях. Например, если в ячейках будут за-
писаны не стоимости ячеек, а длины прыжка из ячейки в следующую вниз или
вправо. Пусть дана таблица:
1 10 10 10
1 1 10 10
1 1 1 1
Как видите из левой верхней ячейки можно сделать ход на один шаг вниз
или вправо. Но из следующей справа ячейки сразу (и только) на 10 ячеек вниз или
вправо, то есть с "вылетом" из таблицы. Такой ход недопустим, а задача форму-
лируется так, чтобы дойти именно до нижней правой ячейки. Так что для приве-
денной таблицы возможны только два пути от входа до выхода (по клеткам стои-
мостью 1).
Как же нужно поступить при решении данной задачи, чтобы успешно приме-
нить принципы динамического программирования?
32
Следующие N строк описывают отдельную строку игрового поля - это за-
писанные через пробел M целых чисел от 0 до 100 – длины шагов из клеток данной
строки.
Выходные данные
Вывести одно число - количество различных вариантов путей от верхнего
левого угла до правого нижнего. Для каждого поля будет менее чем 2^31 различ-
ных путей.
Пример:
№ INPUT OUTPUT
1 3 4 3
2 1 1 2
3 2 1 44
3 1 1 0
1 2 2
34
В правой нижней ячейке записано 2 пути, так как туда будет прыжки из верх-
ней правой ячейки (там длина 2) и из левой нижней (и там длина 2). В предпо-
следние ячейки записаны двойки, так как туда возможны пути только из централь-
ной ячейки, до которой количество путей равно 2.
tab = []
for i in range(n): # ввод исходной таблицы
[Link](list(map(int, input().split()[:m])))
res = [[0]*m for _ in range(n)] # итоговая таблица
res[0][0] = 1
for y in range(n): # все строки
for x in range(m): # все столбцы
step = tab[y][x] # длина прыжка
if step > 0:
if x+step<m: # если в пределах таблицы
# тут добавьте свой код
if y+step<n: # если в пределах таблицы
# тут добавьте свой код
35
9. Алгоритмы на графах
0 1 0
1 2 2 0 1 2
4 3 4 5 6
а) б) в)
36
1. Алгоритмы анализа данных.
Задания для самостоятельного исполнения.
1. Свой-Чужой
Жители племени «Тумба-Юмба» единственные в долине, которые
умеют правильно отвечать на один особенный вопрос. По
правильному ответу их можно отличить от жителей других племён.
Вот этот вопрос: назовите сумму целых чисел от 1 (включительно)
до N (включительно). Не стоит недооценивать задачу, ведь N может
быть отрицательным.
Напишите программу для проверки жителей. На вход в консоли с
клавиатуры вводится одно целое число N (по модулю не более 104), а
на выход – на экран выводится искомая сумма.
2. Дороги
В племени «Тумба-Юмба» есть N точек для охоты, некоторые из
которых соединены тропами. Вождь племени решил провести
инвентаризацию троп. Но, он не силен в математике, поэтому он
просит вас сосчитать количество дорог. Требуется написать
программу, помогающую сосчитать количество дорог по заданной
матрице связности точек.
Входные данные
В первой строке входного файла [Link] записано число N (0
≤ N ≤ 100). В следующих N строках записано по N чисел, каждое из
которых является единичкой или ноликом. Причем, если в позиции (i,
j) квадратной матрицы стоит единичка, то i-ый и j-ый точки охоты
соединены тропами, а если нолик, то не соединены.
Выходные данные
На экран необходимо вывести число, определяющее количество
троп.
Пример.
Если входной файл такой:
5
0 1 0 0 0
1 0 1 1 0
0 1 0 0 0
0 1 0 0 0
0 0 0 0 0
37
то правильный ответ = 3.
3. Прямоугольники
Дети племени «Тумба-Юмба» любят играть в логические игры.
Однажды вождь племени придумал детям задачу на построение
прямоугольников одинаковой площади. Пусть дана площадь
прямоугольника, тогда нужно найти количество различных
прямоугольников с целочисленными длинами сторон заданной
площади. Например, для площади 20 можно построить три
различающихся прямоугольника с такой же площадью.
Итак, пользователь с клавиатуры вводит одно целое
положительное число, не превосходящее 109 – это заданная площадь
прямоугольника. А на экран нужно вывести искомое количество
прямоугольников.
4. Результаты охоты
Вождь племени «Тумба-Юмба» очень аккуратен в подсчёте
успехов на охоте, но он особенным образом записывает результаты. В
местных лесах водятся 9 разных видов животных – они обозначаются
цифрами от 1 до 9. После охоты вождь раскладывает трофеи по видам
животных подряд, например, так:
334555
то есть пойманы две «тройки», одна «четвёрка», три «пятёрки», и,
затем, так же как мы только что назвали результаты, так и записывает
их:
231435
Вождь таким образом шифрует результаты охоты. Помогите
вождю – напишите программу, которая из входной строки будет делать
зашифрованную. Длина входной строки не превышает 100 символов.
5. Ход конём
38
Интеллектуалы племени «Тумба-Юмба»
после охоты учатся играть в шахматы. На
этой неделе они осваивают ход Конём.
Напишите программу, которая будет
проверять правильность хода.
На вход подаётся строка – это шахматная
запись начальной позиции фигуры и
конечной позиции, например, так:
D5-C7
На выход нужно вывести результат анализа записи хода.
YES
- если указанный ход верный,
NO
- если такой ход не по правилам, указанным для Коня.
Гарантируется, что запись хода будет указана корректно, то есть
будет состоять из 5-ти символов, в середине «дефис», буквы и цифры
на правильных местах и в разрешённом диапазоне для шахматной
доски.
6. Шамбала
Шаман племени «Тумба-Юмба» особым даром – он умеет отгонять
беду от посевов племени. Но для успешного камлания он должен в
день начала посевов правильно сложить особенную фигуру,
называемую Шамбалой, чтобы боги погоды были благосклонны к
жителям племени. Как строится Шамбала посмотрите из примеров:
1-й 2-й день 3-й день 4-й день 5-й день
день
39
Попробуйте реализовать рекурсивную функцию заполнения таблицы
«концентрическими кругами».
40
2. Байки Солнечного города.
Задания для самостоятельного исполнения.
1. Тот-кого-нельзя-называть
Чтобы настроение жителей Солнечного города находилось по
«Шкале Счастья» в рамках от Хорошего до Прекрасного достаточно
обеспечить такое распределение зарплат, чтобы коротышка с самой
низкой зарплатой получал не менее 10% от самой большой зарплаты
в городе. Самый активный житель города – Тот-кого-нельзя-называть,
его все так называли, даже мэр города - Тот-кого-нельзя-оскорблять,
решил отслеживать настроение жителей. Помогите ему и напишите
программу.
На вход подаётся последовательность целых чисел (это зарплаты
горожан), например, такая:
600 100 500 1000
на экран нужно вывести отношение самой низкой зарплаты к самой
высокой, выраженное в процентах с округлением до целого.
2. Уравнение Незнайки
Уравнение для Незнайки представляет собой строку длиной 5
символов, например, такую: x+5=7.
Второй символ строки является либо знаком '+' (плюс) либо '-'
(минус), четвёртый символ — знак '=' (равно). Из первого, третьего и
пятого символов ровно два являются цифрами из диапазона от 0 до 9,
и один — буквой x, обозначающей неизвестное.
Требуется написать программу, которая позволит решить данное
уравнение, то есть найти величину x.
На вход подаётся одна строка, например:
3-x=9.
На выход значение x:
-6
3. Нумерология Кнопочки
Как и многие другие коротышки, малышка Кнопочка верит во
всякие чудеса, обожает разные гадания и нумерологию. Кнопочка
руководит солнечногорской гостиницей и считает, что некоторым
особенным клиентам нужно делать значительную скидку, чтобы
коротышечьи боги были благосклонны к её бизнесу. Особенность
41
клиентов определяется по их порядковому номеру заселения
следующим образом: пусть n – номер заселения, нужно подсчитать
сумму всех целых чисел (от 1 до n), на которые n делится без остатка
и, если эта сумма окажется нечётной, то данный гость получает скидку
(если n=3, то 1+3=4 – не особенный гость; если n=4, то 1+2+4=7 -
особенный). Кнопочка не успевает выполнять все обязанности по
гостинице и ей очень нужна программа, которая автоматизирует
процесс вычисления особенных клиентов.
На вход подаётся текстовый файл формата – порядковый номер
клиента, символ табуляции, имя клиента, например:
1 Стекляшкин
2 Пилюлькин
3 Смекайло
4 Растеряйка
5 Молчун
6 Сахариныч
7 Винтик
8 Шпунтик
9 Пачкуля Пёстренький
10 Гусля
11 Винтик
12 Шпунтик
Нужно вывести на экран список Фамилий особенных клиентов.
4. Шифрование Пилюлькина
Пилюлькин решил производить сладкую газировку в
промышленных масштабах, но монополии запрещены в Солнечном
городе. Однако он решил работать через подставные компании, а
рецепт и ингредиенты каждый раз оставлял в одном из номеров
солнечногорской гостиницы. Своим подельникам, Жулио и Нига, из
Лос-Поганоса он передавал лишь шифрованную запись, публикуя её в
«Газете дураков». Запись состоит из последовательности нулей и
единиц без пробелов общей длиной не более 255 символов. Самая
длинная непрерывная цепочка нулей в шифровке Пилюлькина и
обозначала номер, которые должны были снять подельники в
гостинице и там забрать искомые компоненты.
Например, если дана такая последовательность - 00101110000110,
то зашифрован номер 4.
Продажные полицейские солнечногорска не в состоянии
разгадать такой шифр, а, возможно и не хотят, так как они продажные.
Помогите детективу Биглю, не являющемуся полицейским, –
напишите программу, которая по шифру Пилюлькина будет
восстанавливать зашифрованный гостиничный номер.
42
5. Лекции Незнайки
Незнайка регулярно посещает лекции Знайки по истории, но он так
неаккуратно ведёт записи, что это каждый раз становится проблемой
при подготовке к экзаменам. Незнайка решил исправляться - ему нужно
вести статистику своих ошибок, чтобы отслеживать улучшения.
Ошибки Незнайки состоят в том, что он в каждом записываемом
имени допускает ровно одну орфографическую ошибку, то есть
заменяет ровно одну из букв имени какой-то другой буквой.
Пусть дан список правильных написаний имён, и список имён или
других слов из записей Незнайки. Сопоставлять два списка сам
Незнайка не в состоянии. Напишите программу, которая поможет вести
статистику ошибок Незнайки.
Входные данные – это текстовый файл «[Link]».
В первой строке файла находится целое число N – это количество
правильных имён из лекций Знайки. Следующие N строк содержат
правильные имена. Далее идет строка, содержащая целое число M –
количество «подозрительных» имен и слов из записей Незнайки.
Следующие M строк – это те самые имена с ошибкой и слова. Каждое
из имен – последовательность из K заглавных букв английского
алфавита (1 ≤ N, M, K ≤ 30).
По результатам работы программы на экран нужно вывести одну
строку, состоящую из N чисел – для каждого правильного имени
выводится количество «подозрительных слов» из записей Незнайки,
то есть тех, которые отличаются строго на одну букву.
Пример входного файла:
3
ZEUS
POSEIDON
AFINA
4
ZEVS
POSEYDON
AVYNA
ZERS
Вывод на экран:
2 1 0
6. Равнобедренные треугольники
43
Знайка иногда ведёт частные уроки по геометрии и ему нужно
рисовать равнобедренные треугольники. Но это рутинная операция и
Знайке совсем не хочется тратить на это своё время. Помогите ему и
напишите соответствующую программу.
На вход подаётся целое число N в диапазоне от 1 до 30.
По результатам работы программы на экран выводится
равнобедренный треугольник по такому формату: N – это высота
треугольника, основание треугольника параллельно вертикальной
стороне экрана, остальные параметры смотрите по примерам:
Ввод N: 1 2 3 4 5
Вывод: * * * * *
** ** ** **
* * * * * * *
** * * * *
* * * * *
** * *
* * *
**
*
44
3. Безумное чаепитие.
Задания для самостоятельного исполнения.
В этой работе нужно написать функции и разместить их в модуле [Link].
Основная программа должна обращаться к функциям из модуля [Link].
1. Точное время.
Около дома под
деревом стоял накрытый
стол, а за столом пили чай
Мартовский Заяц и
Безумный Шляпник.
Стол был большой,
хорошо сервированный,
готовый к чаепитию.
Однако чаёвники сидели с
пустыми чашками.
Это ничуть не смутило
Алису - она выбрала место сама и, не спрашивая, уселась в удобное
большое кресло.
- Приступим, - дерзко сказала Алиса.
- Мы не можем, - нервно выкрикнул Мартовский Заяц.
- Отчего же? - не унималась Алиса.
- От того, что мы не знаем, когда заварится чай... - с горечью
вымолвил Безумный Шляпник.
Тягостная пауза. Алиса с недоумением смотрит на
присутствующих.
- Ну, вот смотри, - нехотя продолжил Шляпник, вынимая из
кармана часы. - Сколько сейчас времени?
- Полпервого, - уверенно заявила Алиса.
- Что ты, что ты, - засуетился Мартовский Заяц, - твоя
самоуверенность тебя погубит, подытожил он.
Шляпник решил прояснить ситуацию:
- У нас принято всё делать точно. "Сейчас не полпервого"...
Мартовский кот пренебрежительно хмыкнул.
- Сейчас 12.28.05, - уточнил Шляпник.
- А зачем говорить секунды? - продолжала вредничать Алиса.
45
- А затем, глупое создание, что наш чай нужно
заваривать ровно 333 секунды и не секундой
дольше.
2. Палиндромы.
- А что будет, если мы
не уложимся в точное
время заваривания чая? -
никак не унималась
Алиса.
- Ничего хорошего не
будет, - буркнул в ответ
Заяц.
- Он не далёк от
истины, последствия
непредсказуемы, - пояснил Шляпник.
- В прошлый раз время пошло вспять, - продолжил он после паузы,
занятой отхлёбыванием свежеТочноЗаваренного ароматного чая.
- Как же вы выкрутились? - удивилась Алиса.
- А также, ответил Шляпник, - мы знали заранее и подготовились,
мы пользовались только числами, словами и фразами, которые и в
прямом и в обратном направлении читаются одинаково -
46
палиндромами (данный термин имеет греческое происхождение и
обозначает "движущийся обратно").
Например, число «1231» и слово «рокот» - не палиндромы, они
нам не нужны. А вот, число "12321" – палиндром, слово "топот" и фраза
"Аргентина манит негра!" – палиндромы. Их можно использовать при
любом течении времени...
3. Игра.
- О чём вы общаетесь во время чаепития? - спросила Алиса всех
присутствующих.
- Ни о чём! - фыркнул Мартовский Заяц.
- Как так? - озадачилась Алиса.
- Мы не занимаемся пустой болтовнёй, мы думаем... -
многозначительно добавил Шляпник.
- О чём же вы думаете? - с ехидством поинтересовалась Алиса.
- О том, как не проиграть, конечно же! - сорвался Заяц.
47
- Или о том, как победить, - уточнил Шляпник, ну, вот смотри:
загадаю я, предположим, целое число, а ты должна угадать его за
минимальное количество попыток. В попытке ты говоришь мне
предполагаемое число. После каждой твоей попытки я тебе отвечаю
либо "угадала", либо "больше", либо "меньше". В начале игры я выдаю
тебе 10 печенюшек к чаю, за каждую ошибочную попытку ты мне
возвращаешь одну печенюшку. Все печенюшки, которые останутся
после угадывания моего числа, ты можешь использовать при
чаепитии - понятно?
- А если с первой угадаю? - пыталась съязвить Алиса.
- Угадала бы, если бы я загадывал число от 0 до 1, - ухмыльнулся
Шляпник, - я же загадываю трёхзначное число.
4. Шаги.
- Ну, ладно, засиделась я с вами тут, - вздохнула Алиса, - пойду я.
- Не спеши, - резко выпалил Мартовский Заяц.
- А то что? - с угрозой парировала Алиса.
- А то никогда не вернёшься домой, - обречённо ответил Шляпник.
На Алису от неожиданности накатилась волна страха, но она и виду
не подала. Она уже поняла, что с чаёвниками можно обсудить любую
тему, главное не молчать и соображать.
48
- Но я же знаю обратную дорогу, - с осторожностью произнесла
Алиса.
- В том то и дело, что чай наш заваривался на грибах и на обратном
пути твой левый шаг не будет равен правому, будет меняться.
Твой путь можно будет разбить на отдельные отрезки по Х шагов.
Участков будет несколько - болото, тропа, пустырь, лес и т.д., а
последний участок поляна со входом в кроличью нору всегда
находится в тумане, поэтому нужно будет вслепую подходить ко входу
в нору.
Так вот, на каждом из участков мы определим длину шага левой
ногой и правой ногой в сантиметрах, а также количество шагов на
участке, получится примерно вот такая таблица:
55 45 1000
60 62 800
58 47 1100
52 59 500
Если в конце пути знать
насколько больше ты прошагала
одной ногой по сравнению к другой, то
можно будет гарантированно вернутся ко входу в
нору, и ты успешно вернёшься домой!
49
4. Матрица.
1. Код Пифии.
Хакер Нео, не понимая своей миссии в Матрице,
ищет встречи с Пифией. Личная встреча опасна, как и
любое электронное сообщение, так как Нео уже давно
попал под наблюдение Матрицы, и за ним охотится
Агент Смит. Чтобы передавать сообщения, Пифия
размещает их в сети, но адреса документов шифрует.
Описание кода Пифии. Вы знаете, что каждый
символ имеет свой порядковый номер в таблице
символов, таким образом буквы можно заменить на их
номера, а слова на последовательности целых чисел. Например,
рассмотрим кодировку для имени Neo. Первая буква - N в таблице
символов стоит на 78-ой позиции – это и есть её номер. Но Пифия пошла
дальше и стала кодировать эти номера в шестнадцатеричной системе
счисления, то есть нужно заменить 7810 на 4E16, так как
4E16 => 4*161 + 14*160 = 64 + 14 = 7810
Итак, если зашифровать имя Neo кодом Пифии, то
получится такая последовательность: 4E656F, где
каждые два последовательно записанных символа
кодируют одну букву.
Нео проводит дни в ожидании послания от Пифии
– это будет адрес некоторого файла в сети. Однажды
сообщение придёт и нужно будет оперативно его
декодировать.
68747470733A2F2F70636F64696E672E72752F7478742F776F7264732E747874
2. Бинарный поиск.
50
Скачанный на предыдущем этапе файл,
содержит важную информацию – 100, а может
даже 200 тысяч ключевых слов, расположенных
в алфавитном порядке. Нео должен хранить этот
файл и, при получении ключевого слова от
Тринити, найти его позицию в списке слов.
3. Звонок Морфеусу.
После того, как позиция слова ‘матрица’ будет
найдена, её нужно будет передать Морфеусу.
Чтобы Агент Смит не догадался по какому номеру
отслеживать звонок - Морфеус кодирует свой номер с
помощью графических матриц, где для каждой цифры
выделяется прямоугольное поле размером 2 по
горизонтали и 4 по вертикали:
0 1 2 3 4 5 6 7 8 9
** * ** ** ** ** * ** ** **
** ** * * ** * * * **
** * * * * * ** * ** *
** * ** ** * ** ** * ** *
Закодированный таким образом номер телефона может выглядеть как
некий узор:
********** ********* *
******* * * ** * ***
* *** ***** * * ** *
* * *** ****** ***** *
В этом узоре матрицы отдельных цифр размещены подряд без
дополнительных пробелов. Возьмите этот узор, скопируйте и поместите в
текстовом файле [Link]. Напишите программу, которая читает
текстовый файл с узором, распознаёт там образы цифр и выводит на экран
зашифрованный номер телефона.
51
ПРИМЕРЫ ТЕСТОВЫХ ЗАДАНИЙ
52