В этой статье я расскажу про опыт проведения городской школьной олимпиады по программированию.
Идея организовать местную олимпиаду возникла ещё на стадии запуска детской школы программирования. За два года работы стало ещё более очевидно, что счёт идёт на единицы различных соревнований в этом направлении, а значит мало возможностей для проверки учеников, вовлечения вне занятий, дополнительной мотивации результатами. Скажу даже так: в Иркутске нет соревновательных мероприятий для учеников по программированию на scratch, и только одна олимпиада в которой могут участвовать питонисты - “Играем в программистов”.
Казалось, что организовать олимпиаду нужно много ресурсов: найти большое помещение, например договориться с крупной библиотекой, обеспечить техникой, найти преподавателей-волонтёров, обеспечить безопасность и море других мелочей. И это было некоторым камнем преткновения для частного небольшого учебного заведения в части ресурсов. Решение пришло неожиданно - дистанционная олимпиада! В феврале 2020 года пошли слухи про скорую удалёнку, что очные мероприятия запретят и для меня всё стало на свои места.
Теперь про организацию олимпиады:
Задания мы выложили в вконтакте в своей группе 20 марта 2020 года. Время для решения задач дали чуть больше недели - с 20 марта 2020 года по 29 марта 2020 года. Оценку работ планировали провести до 12 апреля 2020 года, даже сомневались не мало ли, но справились всего за 4 дня. При этом участников было чуть больше 100, проверка была ручная(но об этом попозже).
Участников поделили на три категории:
-
младшая ступень (до 7 класса общеобразовательных учреждений включительно, задачи решены на визуальном языке программирования scratch/snap)
-
средняя ступень (до 7 класса общеобразовательных учреждений включительно, задачи решены на любом разрешённом олимпиадой языке программирования)
-
старшая ступень (8-11 классы общеобразовательных учреждений, задачи решены на любом разрешённом олимпиадой языке программирования).
Что же это за такие разрешённые языки. Мы посоветовались с муниципальными коллегами, которые проводят уже больше 15 лет олимпиаду “Играем в программистов” и допустили следующий список:
Язык |
Редактор |
Компилятор |
C++ |
Code: Blocks, VisualStudio |
VisualStudio 2019 |
C# |
Code: VisualStudio |
VisualStudio 2019 |
Pascal |
FreePascal 2.6.2 |
FreePascal 2.6.2 |
Basic |
FreeBasic 0.90.1 |
FreeBasic 0.90.1 |
Java |
NetBeans, Eclipse |
JDK 1.7.0 |
Python |
IDLE |
Python 3.6 |
Учащимся предлагались задания с указанием максимального количества баллов за каждую задачу и примерными тестами к ней. Решения заданий олимпиады должны были предоставить в виде исходного кода на языке программирования. Ничего необычного. Главное - обозначить как правильно называть имена файлов, по опыту преподавания - дети любят творческие названия проектов. Мы прописали в положении к олимпиаде такое правило: Имя файла даётся по следующему принципу: до 5 символов – название учебного заведения с указанием территории, 2 символа – инициалы участника и последний символ – номер задачи. В имени файла можно использовать только латинские буквы и цифры, первый символ – буква. В основном все следовали указаниям. Когда проверяешь сотни работ, у каждого одни задачи решены, другие нет - соблюдение данного пункта очень экономит время на проверке.
На каждую задачу делали по 5 тестов, за каждый пройденный тест начисляли по 2 балла. Разрешили предоставление дополнительных решений задач. За каждое дополнительное решение начисляли 5 баллов при условии, что и основное решение и дополнительное успешно прошли все тесты. Дополнительное решение должно существенно отличается по методу решения задачи. Сделали это для подстраховки, если будут ученики, решившие все задачи и набравшие максимальные баллы. Спойлер - такого не случилось. Отчасти потому что задачи были составлены не одного уровня, а от совсем простых до очень-очень сложных.
Теперь приведём сами задачки и наши варианты решений, которые мы публиковали для учеников своей школы в рамках их образовательной программы вместе с разбором решений.
Разборы решений, ниже под спойлерами сами задачи и код на python
Задача 1
Через ввод с клавиатуры задаётся количество чисел. Затем сами числа передаются через ввод пользователя с клавиатуры и заносятся в готовый пустой список. Составить программу, подсчитывающую среднее арифметическое. Результат записывается в переменную. Визуально(scratch/snap) – на экране отображается результат любым способом (например, функция говорить/думать). Текстовое (python) – результат выводится в консоль на экран.
Примерный тест:
Входные данные: |
Выходные данные: |
5 1 2 3 4 5 |
3 |
Решение 1
a = int(input("Количество чисел:"))
y = 0
for i in range(a):
x = float(input("Число:"))
y += x
y = y / a
print("Среднее арифметическое: " + str(y))
Задача 2
У Кота, Пса и Птицы имеется по некоторому количеству грибов (у всех по разному количеству). Данные по количеству передаются через ввод пользователя с клавиатуры и заносятся в готовый пустой список, где первый элемент - грибы Кота, второй элемент - грибы Пса, третий элемент - грибы Птицы.
Составить программу, определяющую, у кого из них наибольшее количество. Результат записывается в переменную. Визуально (scratch/snap) – на экране появляется персонаж с наибольшим количеством грибов и говорит (функция говорить/думать)) количество грибов. Текстовое (python) – имя персонажа выводится в консоль на экран.
Примерный тест:
Входные данные |
10 30 20 |
20 10 30 |
Выходные данные |
Пёс |
Птица |
Решение 2
s = []
for i in range(3):
griby = int(input())
s.append(griby)
if s[0]>s[1] and s[0]>s[2]:
print("Кот")
elif s[1]>s[2]:
print("Пёс")
else:
print("Птица")
Задача 3
Через ввод с клавиатуры задаётся количество девочек, у которых было по некоторому количеству яблок. Данные по количеству передаются в готовый пустой список. Каждая девочка съела по стольку яблок, каков её порядковый номер.
Составить программу для определения у кого сколько осталось яблок. Результат записывается в список. Визуально (scratch/snap) – на экране отображаются пять девочек (обязательно использование клонов) и говорят (функция говорить/думать) количество яблок. Текстовое (python) – количество яблок выводятся в консоль на экран. По каждой девочке? По порядку отдельной строкой.
Примерный тест:
Входные данные: |
Выходные данные: |
5 10 20 30 40 50 |
9 18 27 36 45 |
Решение 3
girls = int(input())
apple = []
for numgirl in range(1, girls + 1):
a = int(input())
a = a - numgirl
apple.append(a)
for numgirl in range(girls):
print(apple[numgirl])
Задача 4
День недели задаётся через ввод пользователя с клавиатуры числом от 1 до 7. Составить программу, в которой визуально (scratch/snap) – на экране отображается название этого дня любым способом (например, функция говорить/думать). Текстовое (python) – название дня выводится в консоль на экран.
Примерный тест:
Входные данные |
1 |
3 |
Выходные данные |
Понедельник |
Среда |
Решение 4
days = ['Понедельник','Вторник','Среда','Четверг','Пятница','Суббота','Воскресенье']
day = int(input())
print(days[day - 1])
Задача 5
Через ввод с клавиатуры задаётся количество чисел. Затем сами числа передаются через ввод пользователя с клавиатуры и заносятся в готовый пустой список. Сделать программу, изменяющую элементы списка, числа кратные 5 заменять на 2 (умноженную на кратность заменяемого числа), а числа кратные 2 заменять на 5 (умноженную на кратность заменяемого числа). Числа передаются в готовый пустой список. Результат записывается в список. Визуально (scratch/snap) – на экране отображаются все элементы списка любым способом (например, функция говорить/думать). Текстовое (python) – элементы списка выводится в консоль на экран в одну строку.
Примерный тест:
Входные данные: |
Выходные данные: |
6 10 2 6 20 4 5 |
4 5 15 8 10 2 |
Решение 5
nums = int(input())
listnums = []
for i in range(nums):
listnums.append(int(input()))
for i in range(nums):
if listnums[i] % 5 == 0:
listnums[i] = listnums[i] // 5 * 2
elif listnums[i] % 2 == 0:
listnums[i] = listnums[i] // 2 * 5
print(listnums[i])
Задача 6
Условие этой задачи очень простое: вам всего лишь надо определить, сколько клеток находится под боем шахматного коня, одиноко стоящего на шахматной доске. На всякий случай напомним, что конь ходит буквой «Г» — на две клетки по горизонтали или вертикали в любом направлении, и потом на одну клетку в направлении, перпендикулярном первоначальному. Программа получает на вход через вводы пользователя с клавиатуры два числа от 1 до 8 каждое, задающие номер столбца и номер строки, обозначающие позицию коня на шахматной доске. Визуально (scratch/snap) – на экране отображаются любым способом (например, функция говорить/думать) количество клеток шахматной доски, находящихся под боем коня. Текстовое (python) – количество клеток шахматной доски, находящихся под боем коня выводится в консоль на экран.
Примерный тест:
Входные данные: |
Выходные данные: |
1 5 |
4 |
8 1 |
2 |
Решение 6
vozmojnost = 0
stolb = int(input())
stroka = int(input())
# Конь ходит вправо
if stolb + 2 < 9:
if stroka + 1 < 9: # и вверх
vozmojnost += 1
if stroka - 1 > 0: # и вниз
vozmojnost += 1
# Конь ходит влево
if stolb - 2 > 0:
if stroka + 1 < 9: # и вверх
vozmojnost += 1
if stroka - 1 > 0: # и вниз
vozmojnost += 1
# Конь ходит вверх
if stroka + 2 < 9:
if stolb + 1 < 9: # и вправо
vozmojnost += 1
if stolb - 1 > 0:# и влево
vozmojnost += 1
# Конь ходит вниз
if stroka - 2 > 0:
if stolb + 1 < 9:# и вправо
vozmojnost += 1
if stolb - 1 > 0:# и влево
vozmojnost += 1
print(vozmojnost)
Задача 7
Заданы две клетки шахматной доски. Если они покрашены в один цвет, то выведите слово YES, а если в разные цвета — то NO. Программа получает на вход через вводы пользователя с клавиатуры четыре числа от 1 до 8 каждое, задающие номер столбца и номер строки сначала для первой клетки, потом для второй клетки. Визуально (scratch/snap) – на экране отображаются любым способом (например, функция говорить/думать) YES или NO. Текстовое (python) – выведите YES или NO в консоль на экран.
Примерный тест:
Входные данные: |
Выходные данные: |
1 1 2 6 |
YES |
Решение 7
summ = 0
for i in range(4):
summ += int(input())
if summ % 2 ==0:
print('YES')
else:
print('NO')
Задача 8
На ипподроме наметилось городское соревнование. Но никто не знает сколько будет участников. Места всем хватит, но есть проблема с расширением стартового загона. Представьте загон в виде квадратной таблицы. Участника номер один необходимо ставить в правом верхнем (переднем) углу, далее участников ставят по диагоналям сверху вниз, последний участник стоит в левом нижнем углу. Чтобы быстро сделать расстановку необходимо вывести на табло данную таблицу. Организатор в последний момент сообщит Вам только количество участников (программа получает на вход через ввод пользователя с клавиатуры одно число).
Визуально (scratch/snap) – на экране рисуется таблица, в каждой ячейке вместо обычных чисел используйте точки, какое число – столько сгруппированных точек в ячейке. Текстовое (python) – вывести в консоль на экран таблицу с числовой расстановкой.
Примерный тест:
Входные данные: |
Выходные данные текстовое: |
9 |
4 2 1 7 5 3 9 8 6 |
Решение 8
vvod = int(input())
num = vvod ** 0.5
if int(num) != num:
num = int(num) + 1
else:
num = int(num)
table = [[0] * num for i in range(num)]
numb = 0
ivert = num
for i in range(num):
if ivert > 0:
igoriz = 0
for i in range(num - ivert + 1):
if igoriz <= num - ivert:
numb += 1
if numb <= vvod:
table[igoriz][ivert + igoriz - 1] = numb
else:
table[igoriz][ivert + igoriz - 1] = 0
igoriz += 1
ivert -= 1
ivert = 1
for i in range(num - 1):
if ivert < num:
igoriz = 0
for i in range(num - ivert):
if igoriz < num - ivert:
numb += 1
if numb <= vvod:
table[ivert + igoriz][igoriz] = numb
else:
table[ivert + igoriz][igoriz] = 0
igoriz += 1
ivert += 1
for row in table:
for elem in row:
print(elem, end=' ')
print()
Задача 9
В наш город приехал чудо-зоопарк с множеством зверей. Одних только пингвинов 3 вида, 4 вида черепах, 5 видов акул и т.д. Вы весь день записывали названия животных в блокнот, а вечером решили подсчитать каких животных (не разделяя на виды) было больше всего. Сколько в блокноте всего животных неизвестно, но точно понятно, что каких-то животных больше и что сначала записано животное, а затем его вид, например, «Penguin Emperor». В каждой из следующих строк блокнота записано по одному виду животного. На вход подаётся файл input.txt с данными. Для scratch/snap в программе необходим пустой список для ручного импорта в него файла. Визуально (scratch/snap) – на экране отображаются любым способом (например, функция говорить/думать) название животного и их количество. Текстовое (python) – в консоль на экран в одну строку выводится название животного и их количество.
Примерный тест:
Входные данные: |
Выходные данные: |
Penguin Emperor Shark zebra Turtle Caiman Shark white |
Shark 2 |
Решение 9
file = open("input.txt")
animal=[]
kolvo=[]
for stroka in file:
data = stroka.split()
animal.append(data[0])
for i in animal:
kolvo.append(animal.count(i))
maxi = 0
pos = 0
for i in range(len(kolvo)):
if kolvo[i] > maxi:
maxi = kolvo[i]
pos = i
print(animal[i], maxi, end=" ")
Задача 10
Поговаривают, что сейчас самая популярная игра у школьников - brawl stars. Ты наверняка чемпион и прокачал множество персонажей. Близится соревнование и поэтому надо разбить персонажей на две равные команды. У вас есть несколько персонажей известного уровня w1, …, wn. Напишите программу, которая распределит персонажей в две команды так, что разность суммы уровней этих двух команд будет минимальной. Ввод содержит уровни персонажей w1, …, wn (1 ≤ wi ≤ 100) через пробел с именами персонажей. На вход подаётся файл input.txt с данными. Для scratch/snap в программе необходим пустой список для ручного импорта в него файла
Ваша программа должна вывести имена персонажей первой команды, затем одно число — минимальную разность уровней двух команд. Затем имена персонажей второй команды.
Визуально (scratch/snap) – вывод последовательно заносится в список. Текстовое (python) – ответ выводится в консоль на экран отдельными строками.
Примерный тест:
Входные данные: |
Выходные данные |
4 Shelly 7 Bull 10 Bo 12 8-bit 15 ElPrimo 20 Tick |
Tick Bo Shelly 0 ElPrimo 8-bit Bull |
Решение 10
file = open("input.txt")
pers_dict = []
for pers in file:
data = pers.split()
pers_dict.append((data[1], int(data[0])))
pers_dict.sort(key = lambda elem: elem[1], reverse = True)
command1 = []
command2 = []
summa1=0
summa2=0
for elem in pers_dict:
if summa1 <= summa2:
command1.append(elem)
summa1 += elem[1]
else:
command2.append(elem)
summa2 += elem[1]
for key in command1:
print(key[0])
if summa1> summa2:
print(summa1-summa2)
else:
print(summa2-summa1)
for key in command2:
print(key[0])
Какими выводами хотелось бы поделиться по итогам:
-
Организовать городскую олимпиаду просто, сделайте её дистанционной, не переживайте за гугление участниками, разработайте свои задачи и тогда нагуглить решение будет в разы сложнее, чем решить.
-
Финансирование олимпиады - дело минимальное, берите пример с Роббо, они Российскую олимпиаду по scratch проводят мега бюджетно - электронные дипломы и сертификаты участника с факсимиле организатора, но сути это не меняет - красивая электронная "бумажка" в наличии.
-
Не нужно придумывать автоматизированную проверку, не так страшно ручное тестирование решений. Главное заранее подготовьте тесты.
-
Думаете будет мало участников? Разошлите электронные письма в школы города. Всегда найдётся педагоги, которые очень заинтересованы в таких мероприятиях.
-
Наша олимпиада оказалась очень сложной для школьников всех возрастов, хотя я переживал об обратном. Реально полезной оказалась градация задач по сложности. Задачи 8-10 можно смело забыть, вместо них мы решили в будущем добавить 6 простых задач, схожих по уровню с 4 задачей.
Я очень надеюсь, что статья будет полезной руководителям кружков программирования и педагогам. Смело проводите местные олимпиады, смотрите решения ваших учеников, делайте выводы для улучшения своей образовательной программы.
Автор: Евгений Бутырин