Про ЕГЭ и программирование.     К списку статей

     Много копий поломано в битве дискуссий об обучении программированию в школе. Какой язык выбирать, как глубоко его изучать, какие задачи программировать и так далее и так далее. Я учитель информатики в обыкновенной школе, и так как нахожусь на самом переднем крае этого фронта, тема для меня очень актуальна. Я не буду рассказывать о тонкостях учебного процесса при обучении программированию. Сегодня мне хотелось бы коснуться критерия оценки качества создаваемых программ. А как мы можем узнать о качестве подготовки учащихся в вопросе программирования? Да, конечно же, из ЕГЭ.
     В демонстрационном варианте для ЕГЭ 2009 по информатике имеется несколько заданий, которые предназначены для проверки у выпускников наличия навыков программирования. Остановимся подробней на задании C4.
     С первой же строки задание вводит нас в заблуждение, а затем девятью строками его углубляет. В нем утверждается, что на вход программе будут подаваться сведения о номерах школ, а затем рассказывается, что номер это часть сведений об ученике.
     Я не профессиональный постановщик, но задание на написание программы по учету участников школьных олимпиад,
я бы выдал таким.
     Требуется составить программу для учета участия школьников в олимпиадах. Количество участников около 1000. Формат предоставляемых сведений следующий: Фамилия - не более 20 символов, инициалы - 4 символа, номер школы - число до двух знаков. Фамилия, инициалы и номер разделены пробелом. По исходным данным определить школы, приславшие наименьшее количество участников. (Информацию о школах-участниках сохранить в файле.)

Приведу пример программы из демонстрационного варианта.

var nc:array[1..99] of integer;
p:1..99;
c:char;
i, k, N, min: integer;
begin
readln(N);
for i:=0 to 99 do nc[i]:=0;
for i:=1 to N do
begin
repeat
read(c)
until c=’ ’; {считана фамилия}
repeat
read(c)
until c=’ ’; {считаны инициалы}
readln(p);
nc[p]:=nc[p]+1;
end;
min:=N;
for i:=1 to 99 do
if nc[i]>0 then
begin
if nc[i]<min then min:=nc[i];
end;
for i:=1 to 99 do
if nc[i]=min then
writeln(i);
readln
end.


     Представленная выше программа выглядит очень эффектно, об эффективности разговор дальше. Тут вам и экономия памяти - вводимые данные нигде не сохраняются, и посимвольный контроль ввода, и использование перечисляемых типов данных, программа выдает на экран только самые неблагополучные школы. Я мог бы еще рассказать об элегантности алгоритма и кода. Чего стоит, например, допуск о том, что вся тысяча участников явилась на олимпиады из одной школы.
     Давайте спустимся с небес на землю и попытаемся разобраться в сути задания. Что такое тысяча участников? Это всего скорей информация о районных олимпиадах приличной области. Значит, информацию о ней заносили где то в облоно. Около 30 символов на участника, итого 30000 символов. Даже при очень неплохой скорости в 3 символа в секунду - 10000 секунд: около 3х часов выходит. И вся эта свистопляска только для того, чтобы увидеть на экране, например: 7
     И эта программа приводится, как наиболее эффективная. А что означает сия цифра на экране? Что седьмая школа - бяка! А еще это означает, что школьники, став программистами, должны писать именно такие программы.
     А что если на пятисотом участнике в блоке вводимых данных возникнет лишний пробел, или номер школы введут со значком номера.
     Кто-то скажет: все у него плохо, а сам то, что предложишь. А я и не увиливаю. И покажу вам совершенно простую и "неэффектную программу", которая сделает то же самое, но по-другому.
     Почему, например, такой большой объем ввода нигде не сохраняется, это нелогично, хоть бы данные обо всех этих учениках просто в файл сбросить, ведь, наверняка, потом может потребоваться из них какие-то сведения получить. И, что же опять все это заводить? Ну, если задание говорит, что, не надо, значит не надо.

Var
uch : string [30];
A : array [1..99] of integer;
Min, N, K, I, T : Integer;
Stmp : String;
F : text;

Begin

For I:=1 to 99 do A[I]:=0;
Min:=1;

Writeln('Введи количество участников');
Readln(N);

For I:=1 to N do
Begin
Write(I,' - ');
Readln(Uch);
Stmp:=Copy(Uch,Length(Uch)-1,2);
If Copy(Stmp,1,1)=' ' then Delete(Stmp,1,1);
Val(Stmp,K,T);

A[K]:=A[K]+1;
IF Min < A[K] then Min:=A[k]; {Максимальное количество участников от школы}

End;

For I:=1 to 99 do
If (Min > A[I]) AND (A[I]<>0) then Min:=A[I];

For I:=1 to 99 do
If A[I] = Min then Writeln('От школы N', I, ' - ', min, ' учеников.');

Assign(F, 'spis.txt');
Rewrite(F);
For I:=1 to 99 do
If A[I] <> 0 Then Writeln(F, I, ' - ', A[I]);
Close(F);

readln;

End.

     Моя программа немного больше по размерам. Но я готов вам рассказать о ее функциональности.
Компилироваться она будет в любом Паскале, так как не использует никаких экстравагантностей, типа динамических массивов. Приведенная в качестве примера программа, впрочем, тоже.
     Далее следует объявление необходимых переменных, назначение которых будет пояснено ниже.
В начале программы готовим массив A участников по школам, заполняя его нулями. А также выставляем минимум регистрации участия в количестве одного ученика.
     Затем запрашиваем количество участников олимпиад и помещаем это значение в переменную N.
Теперь спокойно организуем цикл по заполнению нашего массива данными о школах.
Рассмотрим этот цикл подробнее. Сколько еще таких циклов для ввода разных сведений может встретиться начинающему программисту?
     Информация о том, какого участника мы в данный момент вводим, очень информативна, а размер кода минимален.
     Выборка номера школы из введенной строки, на первый взгляд кажется громоздкой и неуклюжей, но на самом деле она проста, наглядна и универсальна. Происходит выделение 2-х символьной подстроки из исходной (номер то может быть двухзначным), удаляются лишние пробелы и строка преобразуется в число. Вот и все премудрости. По правилам хорошего тона полагалось проанализировать переменную T, чтобы убедиться, что преобразование выполнено верно. Иначе попросить оператора на вводе уточнить данные.
     Дальше увеличиваем количество участников из этой школы на 1. Можно это сделать более модным способом Inc(A[I]).
     А как нам определить, кто прислал всех меньше. Можно взять минимальное количество участников (1) и поискать его в списке, если такие школы есть то их и показывать, если нет увеличить порог на 1 и повторить поиск. Я решил сделать по-другому, найти сначала тех, кто прислал всех больше, хотя задание этого и не требует, но эта операция совершенно логично вписывается в процесс регистрации участников.
     Затем, исходя из этой цифры, мы находим наихудший показатель. Ну и, наконец, просто выводим наименее активные школы.
     Я позволил себе вставить код сохранения данных об участниках по школам в файл, чтобы показать, что это ненамного удлиняет программу, но придает ей вид полезного инструмента, а не просто программистского эксперимента.
     Можно заметить, что также просто можно было сохранить данные и по ученикам.
Да, согласен, код не столь элегантен, но с точки зрения практичности, не идет с образцом ни в какое сравнение.
    Только удовлетворит ли она спецов от ЕГЭ?

Но программирование это процесс творческий. Вот еще один вариант в духе эффективности.

Хотя в задании сказано, что на вход программе подаются данные, как выясняется из образца, эти данные вводятся с клавиатуры. Вообще-то на вход программе данные могут попасть разными способами: например из файла. В этом случае фильтрация ввода из программы образца работать не сможет. Но в задании ввод никак конкретно не оговорен (а хотелось бы, ведь это не творческая олимпиада). В требуемых результатах фамилии и имена учеников не участвуют, а потому мы их можем игнорировать. Тогда программа упрощается. Минимальное участие в олимпиадах определяется последовательным увеличением этого значения до определения его актуальности. Остальные части программы вполне наглядны.

Var
A : array [1..99] of integer;
Min, N, NS, I : Integer;
F : Boolean;

Begin

For I:=1 to 99 do A[I]:=0;
Min:=0;
F:=False;

Readln(N);

For I:=1 to N do
Begin
Readln(NS);
Inc(A[NS]);
End;

While Not F do
Begin
Inc(Min);
For I:=1 to 99 do
If A[I] = Min then F:=True;
end;

For I:=1 to 99 do
IF A[I] = Min Then Writeln('School - ',I);

readln;

еnd.


Я свое слово сказал, кто следующий?


Николай Коротков (NK). Учитель информатики. Школа N1. Город Наволоки, Ивановской области.
E-mail: draginf@mail.ru