понедельник, 9 ноября 2015 г.

Районная олимпиада по программированию (10-11 класс)

Самое главное: из 6 участников от нашей школы все 6 заняли призовые места!


Поздравляю победителей!
Марк Приймак - 10 класс - 1 место
Павел Карлин - 10 класс - 2 место
Александр Купченко - 8 класс - 2 место
Максим Васильев - 8 класс - 2 место
Лев Ливинский - 11 класс - 3 место
Константин Устименков - 8 класс - 3 место


А теперь разберем, что было сделано не совсем так, и как надо было сделать правильно.

Задача 1.

Палиндром. Палиндром, Карл! Смотрим СЮДА, Паша - молодец, повторил перед олимпиадой!

Задача 2.

Цветное изображение имеет N цветов. Размер изображения AxB см. Разрешение R точек на дюйм (1 дюйм = 2,54 см).
Определить, сколько Кбайт памяти нужно для хранения изображения в несжатом виде?

Входные данные
Первая строка содержит натуральное число N количество цветов. Следующие две строки содержат действительные числа, которые задают размер фотографии. Последняя строка содержит натуральное число, которое задает разрешение. Все числа входного файла по абсолютной величине не превышают 1000000000.

Выходные данные
Единственная строка файла содержит искомый размер фотографии, как действительное число с двумя знаками после запятой.

Пример входных и выходных данных
input.txt
output.txt
8
10
15
30
766.29
Решение
Для решения задачи необходимо определить количество бит занимаемая точка и подсчитать их количество. Для определения количества бит используется соотношение n=2k (где n — количество точек, k — количество бит), отсюда


Т.е. мы получаем логарифм по основанию 2 числа n, но, поскольку Паскаль не умеет считать логарифмы по произвольному основанию, по правилам работы с логарифмами приводим нужный результат к натуральным логарифмам, с основанием  числа Эйлера, мы об этом говорили.

Данная формула используется для определении количества двоичных кодов в бинарном дереве.
n
b
2
4
8
16
32

256
65536
16777216
1
2
3
4
5

8
16
24

В итоге, с логарифмами это решается так:

program photo;
var bit,n,a,b,r:integer;
k:real;
f1,f2:text;

begin
assign(f1,'photo.dat');
reset(f1);
read(f1,n,a,b,r);
close(f1);

bit:=round(ln(n-1)/ln(2)+1);
k:=(a/2.54)*(b/2.54)*r*r*bit/8/1024;
k:=int(k*100)/100;

assign(f2,'photo.sol');
rewrite(f2);
writeln(f2,k:2:2);
close(f2);
end.

Можно решить БЕЗ логарифмов. Тогда программа будет выглядеть так:

program photo;
var bit,n,a,b,r:integer;
k:real;
f1,f2:text;
begin
assign(f1,'photo.dat');
reset(f1);
read(f1,n,a,b,r);
close(f1);
bit:=1;
n:=n-1;
while n>1 do begin
bit:=bit+1;
n:=n div 2;
end;
if n>2 then bit:=bit+1;
k:=(a/2.54)*(b/2.54)* r * r * bit/8/1024;
k:=int(k*100)/100;
assign(f2,'photo.sol');
rewrite(f2);
writeln(f2,k:2:2);
close(f2);
end.

Знать математику - выгоднее, чем не знать. Задание: объяснить, в чем разница между двумя вариантами программы.

Задача 3.

Из одного порта в другой необходимо перевезти 15 различных грузов. Грузоподъемность судна, на котором будет проходить перевозка, 50 тонн. Грузы пронумерованы, и информация о массах грузов хранится в массиве М(15). Определить, сколько рейсов необходимо сделать судну, если грузы неделимы и могут перевозиться только подряд в порядке их нумерации. (Предполагается, что масса отдельного груза не превышает 50 тонн). 

Смысл решения: берем кораблик номер  k и начинаем в него закладывать грузы по порядку. Если сумма того, что там уже есть, и масса текущего груза превышают 50, мы отправляем текущий кораблик, добавляем к k единичку и начинаем грузить дальше с того груза, который не влез в предыдущий кораблик.

program z3;

var
   m:array[1..15] of integer;
   k,i,s:integer;

Begin
   for i:=1 to 15 do
      begin
         writeln ('Введите m','[',i,']');
         readln (m[i]);
      end;

      k:=1; i:=1; s:=0;
Внимание! Используем цикл   repeat - until. Подробности - в словаре сайта.
      repeat
         if s+m[i]<=50 then
           begin
             s:=s+m[i];
             i:=i+1;
           end
              else
                 begin
                   k:=k+1;
                   s:=0;
                 end;
       until i>15;

       writeln ('Потребовалось ', k,' рейсов');
end.

Очень рекомендую сходить на сайт: Олимпиады по информатике
И скачать и разобрать задачи с решениями

Районная олимпиада по программированию - 2015 (8-9 класс)

Самое главное: из 6 участников от нашей школы все 6 заняли призовые места!


Поздравляю победителей!
Марк Приймак - 10 класс - 1 место
Павел Карлин - 10 класс - 2 место
Александр Купченко - 8 класс - 2 место
Максим Васильев - 8 класс - 2 место
Лев Ливинский - 11 класс - 3 место
Константин Устименков - 8 класс - 3 место


А теперь разберем, что было сделано не совсем так, и как надо было сделать правильно.

8-9 класс.

Задача 1.

Найти наибольшее отношение трехзначного числа к сумме его цифр.

Решение.
1. Давайте уточним условие. Вы не просите пользователя вводить числа. Это должен сделать компьютер. Причем компьютер должен перебрать все числа от 100 до 999, для каждого считая результат: ЧИСЛО/(Сумму его цифр)

2. На экран требуется вывести только то число, для которого результат из пункта 2 окажется максимальным.

Основная ошибка наших олимпиадников (впрочем. не только наших) - непреодолимое желание поговорить с пользователем. При этом найдя проблемы на свою голову.

Если вам вводят число с клавиатуры, вы должны делить его на разрядные единицы - сотни. десятки, единицы - чтоб потом считать сумму. Я не знаю автора работы, который вплотную приблизился к решению задачи, но все равно сделал не так. как надо. Он упорно считал результат для каждого введенного числа. Но на экран выводил примерно следующее:

Вы ввели число 123
Результат для вашего числа 20,5

НАИБОЛЬШЕЕ ОТНОШЕНИЕ трехзначного числа к сумме его цифр имеет число 100. 
100/1 = 100.

Ребенок вручную посчитал результат и просто сообщал его каждому зашедшему в его программу.

Что НАДО было сделать? Надо было, чтобы компьютер ПЕРЕБРАЛ все варианты от 100 до 999 и выбрал максимальный результат.

Как это нужно было сделать?
Заказываем необходимое количество переменных нужных типов. 
Var
i,j,k,a,b,sum:integer;
max,d:real;

begin
max:=0;  Считаем, для начала, что максимальный результат 0.
a:=0;
b:=0;

А вот тут мы начинаем создавать наши числа, меняя сотни, десятки и                                             единицы. i будет отвечать за количество сотен, поэтому начинается с 1, j будет заведовать десятками, начинается с 0, и k займется единицами, тоже с нуля - таким образом первое из полученных нами чисел будет (i*100+j*10+k), т. е. 100.

For i:=1 to 9 do begin   
  for j:=0 to 9 do begin
    for k:=0 to 9 do begin
     
Сразу считаем сумму цифр. Потом делим наше число на эту сумму. Результат запоминаем в d.
     sum:=i+j+k;
     d:=(i*100+j*10+k)/sum;
Если d оказалось больше максимума, мы запоминаем само число в   a, запоминаем сумму цифр в     b, и меняем максимум на этот улучшенный результат. 
     
 if d>max then 
      begin
        max:=d;
        a:=i*100+j*10+k;
        b:=sum;
        end;
     end;
    end;
   end;

Когда мы отработали все циклы, уже можно поговорить с пользователем - вывести ему сообщение.
   
 Writeln ('Maximum = ',max,' pri delenii ',a,' na ',b);
 end.

Вот и все.


Задача 2.

Дана строка, состоящая из символов, каждый из которых является знаком «+» или цифрой, начинающаяся и заканчивающаяся цифрой. Если в строке встречается сочетание «++», то выдать сообщение об ошибке, в противном случае вычислить получившуюся сумму.

var
  i,res: integer;
begin
  res:=0;
  for i := 1 to length(s) - 1 do
    if (s[i] = '+') and (s[i+1]= '+' ) then
      begin
        write('Error');
        exit;
      end;
  for i := 1 to length(s) do
    if s[i] <> '+' then 
res:= res + StrToInt(s[i]);
  write(res);
end.

Эта задача рассчитана больше на знание языка программирования, чем  на сообразительность. Для решения задачи можно использовать функцию "ORD", которая позволяет получить порядковый номер любого символа согласно таблице ASCII-кодов. Например, номер символа '0' - 48, а номер символа '1' - 49. Как вы понимаете, чтобы получить искомую цифру, необходимо отнять от номера символа 48.

Внимание!
  1. Во входной строке нет пробелов!
  2. Функция ORD будет работать в Turbo Pascal, но не будет работать в Pascal ABC.
  3. Pascal ABS поддерживает синтаксис Delphi, поэтому необходимо заменить строку "res:= res + (ord(s[i])-48);" на "res:= res + StrToInt(s[i]);"

Задача 3.

Между школами поделили N компьютеров Pentium и M компьютеров Celeron. 
Сколько было школ, если известно их не менее K и каждая школа получила 
одинаковое количество компьютеров каждого вида.
Все числа входного файла не превышают 1000000000.
Входные данные
Первая строка содержит натуральные числа N, M, K.
Выходные данные
Единственная строка файла содержит найденное количество школ. Если результатов несколько, то вывести все через пробел в возрастающем
порядке.
Пример входных и выходных данных

input.txt
output.txt
92 138 25
46
Решение
Необходимо найти общие делители чисел M и N, не меньше числа K.
var i,n,m,k,min:integer; f,g:text;
begin assign(f,'input.txt'); reset(f); read(f,n,m,k); close(f);
assign(g,'output.txt'); rewrite(g);
if n>m then min:=m else min:=n;
for i:=k to min do begin if (n mod i=0)and(m mod i=0) then write(g,i,' '); end;
writeln(g); close(g);
end.
В принципе, с задачами 8-9 класса - все. Разобрать. Задать вопросы. Поехали!
Домашняя работа: изучить сайт с олимпиадами за 3 последних года: 

Скачать и разобрать : задачи с решениями

пятница, 5 декабря 2014 г.

Треугольник Паскаля

Сегодня мы рассмотрим не сложную, но интересную задачу - построение "Треугольника Паскаля".

Вы из курса математики знаете такие формулы сокращенного умножения:

(a + b)2 = a2 + 2ab + b2

(a + b)3 = a3 + 3a2b + 3ab2 + b3

Теперь давайте посмотрим на картинку, изображающую треугольник Паскаля:

какая связь между цифрами в каждой из строк треугольника и приведенными выше формулами? Догадались? Проверяем!


Правильный ответ - в каждой строке треугольника значения коэффициентов для возведения суммы в соответствующую степень.

Теперь установите закономерность формирования элементов каждой строки. Для этого внимательно посмотрите на значения той строки, которая выше.

Проверьте свой вывод по картинке:


Теперь давайте сформулируем вывод на языке информатики. 
Пусть каждый элемент треугольника обозначается как a[ i , j ], где  a - сам элемент,  i - номер строки, в которой он находится, а j - порядковый номер этого элемента в строке. Например, обведенные в красные кружки элементы - это a[ 3 , 2 ] = 2 и a[ 7 , 3 ] = 15.
Мы не можем использовать строку с номером 0, поэтому наша нумерация строк будет на 1 больше степени n на приведенном рисунке.

Тогда мы можем сделать вывод, что ПОЧТИ каждый элемент треугольника - это сумма элементов строкой выше, один из которых идет под тем же номером, что и искомый элемент, а у второго номер на 1 меньше.

Слово ПОЧТИ в утверждении выше указывает на то, что первый и последний элементы в каждой строке равны 1, вне зависимости от номера строки.

Из всего вышесказанного вытекает задание:

Написать программу, которая из входного файла будет считывать n - степень, до которой строится треугольник, а файл вывода будет содержать треугольник Паскаля из n + 1  строк - мы выше говорили, что 0 степень есть, а 0 строки нет.

Например, в файле ввода число 8.

Тогда файл вывода должен выглядеть так:


Можете проверить результат для 8 степени, сверив с рисунком выше.

Обратите внимание, для облегчения задачи я не прошу вас строить равнобедренный треугольник. Пусть будет прямоугольный. Но, если сделаете как на рисунке с объяснением понятия треугольника Паскаля - считайте, плюс два балла к оценке у вас есть.

И еще одна подсказка.
На самом деле я заполняю не треугольник, а квадрат. Просто после последней в строке единицы у меня в программе идут нули, которые я не вывожу на экран.

Если самостоятельно справиться - не судьба, смотрим решение задачи по ссылке.

Но давайте сначала самостоятельно, да?! Удачи!

суббота, 29 ноября 2014 г.

Задачи районной олимпиады по программированию. Задача 11_2

Итак, полное условие задачи:

     В I туре Интернет-олимпиады по программированию n учеников все задачи решили верно, но время выполнения у всех было разным: X1, X2, X3,...Xn, (Xi - натуральное число, время выполнения работы i-ым участником,  n <20). Как выяснилось, у тех, кто справился с заданием быстрее, и решение было более эффективным. Задания можно было решать на протяжении двух дней. 

Задание: Жюри необходимо выбрать четырех программистов с лучшим результатом для участия во II туре олимпиады, при этом необходимо указать номера, под которыми они принимали участие в олимпиаде.

Формат входных данных: В файле input.txt в первой строке - количество учеников, которые все выполнили, а в остальных n строчках - результаты: X1, X2, X3,...Xn

Формат выходных данных: В файле output.txt 4 строки, каждая содержит по два числа через пробел: первое число в строке - один из четырех лучших результатов, второе число - номер участника олимпиады, имеющего этот результат.

Решение:

Давайте сначала еще раз прочитаем условие. Красным цветом я выделю те слова, которые нас действительно интересуют.

  В I туре Интернет-олимпиады по программированию учеников все задачи решили верно, но время выполнения у всех было разным: X1, X2, X3,...Xn, (Xi - натуральное число, время выполнения работы i-ым участником,  n <20). Как выяснилось, у тех, кто справился с заданием быстрее, и решение было более эффективным. Задания можно было решать на протяжении двух дней. 

Задание: Жюри необходимо выбрать четырех программистов с лучшим результатом для участия во II туре олимпиады, при этом необходимо указать номера, под которыми они принимали участие в олимпиаде.

Какие действия, исходя из этого, должна выполнять программа?
  1. Открыть файл с входными данными.
  2. Считать первое число в файле - это n, относительно которого с этого момента мы будем запускать все наши циклы.
  3. Открыть цикл от 1 до n и считывать результаты участников. ВНИМАНИЕ! В этом пункте скрывается первая тонкость - нам недостаточно запомнить результаты участников. Нам надо еще запомнить их номера. На этом этапе номера, конечно, будут совпадать с переменной i, которая является счетчиком цикла, но, по условию задачи, далее будет необходимо провести сортировку результатов. При этом положение элементов в массиве изменятся, а значит их исходные номера проще запомнить в отдельный массив. Предлагаю результаты запоминать в массив X, а номера участников в массив Y. 
  4. Получив исходные данные, мы можем закрыть файл input.txt.
Решение, приведенное далее, далеко не самое рациональное. Но для тех, кто познакомился с основами программирования два месяца назад, более важно, что данное решение а) верно выполняет поставленную задачу; б) использует те команды и методы, которые известны начинающим программистам на данном этапе. 

     5. Предлагаю завести еще один массив. Например, Z. И заполнить его элементами массива X. На данном этапе массивы Z и X полностью совпадают.

      6. Применим к массиву Z сортировку по возрастанию: самый маленький по значению элемент должен оказаться на 1 месте, самый большой по значению - на последнем. Как сортировать одномерные массивы мы говорили в ЭТОМ занятии.

     7. Теперь мы могли бы уже вывести в нужном порядке результаты четырех победителей. Но ведь по условию задачи каждый из результатов должен сопровождаться номером участника олимпиады, показавшего этот результат. И вот тут нам поможет то, что исходные и отсортированные данные хранятся в разных массивах. Я предлагаю такую конструкцию:



For i:=1 to n do

For j:=1 to n do

if z[i]=x[j] then

m[i]:=y[j];

Первый цикл (по i) перебирает отсортированный массив Z. При этом мы берем, допустим, на первом шаге Z[1] и, благодаря внутреннему циклу по j, сравниваем этот элемент со всеми элементами массива X. Когда мы считывали массив X, напомню, в отдельный массив, Y, мы сохраняли номер участника олимпиады. Так вот, используя еще один массив, M, мы записываем в элемент массива М с номером, равным номеру проверяемого Z, номер участника, который соответствует X, совпавшему с Z.

8. Осталось только вывести результат в соответствующий файл.

Напишите код к этой задаче самостоятельно и проверьте работу задачи. Если не получится - смотрите решение ЗДЕСЬ

САМОСТОЯТЕЛЬНО:

Продумайте решение задачи с меньшим количеством дополнительных массивов.

суббота, 15 ноября 2014 г.

Задачи районной олимпиады по программированию. 11 класс задача 1.

Задача 1. Клякса.

Когда Чебурашке исполнилось 6 лет, Крокодил Гена пригласил его в свою школу. Чебурашка очень обрадовался, и отправился навстречу знаниям. По дороге к нему пристала очень любопытная и назойливая старуха Шапокляк. Чебурашку ничего не оставалось делать, как взять её с собой.
Когда они пришли в школу, Крокодил Гена повёл их на урок математики. Чебурашка открыл свою новенькую тетрадь в клеточку и достал чернильницу. Шапокляк не выдержала и сунула в чернильницу свой длинный нос, и на чистотой странице в клеточку появилось N синих пятнышек. Чебурашка очень расстроился, но Гена его сразу успокоил. Он предложил заклеить все кляксы одной белой прямоугольной бумажной лентой так, чтобы стороны ленты были параллельны сторонам клеточки, а её площадь была минимальной.

Задание. Необходимо найти координаты левой нижней и правой верней вершин этой ленты.
Формат входных данных. В файле input.txt в первой строке записано число N- количество пятнышек-клякс (2< =N<=100). В следующих N строчках, через пробел, введены значения координат Xi.Yi(/Xi/,/Yi/<=10 в 9 степени) .
Формат выходных данных. В файле output.txt в одной строке выведены координаты правой верхней и левой нижней вершин прямоугольной ленты.

К чему сводится задача?

Даны различные координаты точек. Количество точек n мы узнаем из первого прочтенного числа в входном файле. С этого момента мы можем создавать циклы 

For i:=1 to n do

Необходимо найти максимальные и минимальные значения для координат X и Y, и вывести в файл вывода 4 числа: Xmax, Ymax, Xmin, Ymin.

Решите эту задачу самостоятельно. Если не получится - смотрим в решение.



Задачи районной олимпиады по программированию. Разбор задачи 3.

Задача про нефтяные пятна 

бродит по интернету с 2010 года. Вот ее условие:

После аварии на морской нефтяной скважине в океан вылилось много нефти. Она растеклась по воде, после чего образовалась определенное количество нефтяных пятен. Для ликвидации последствий аварии был создан штаб по координации действий. Сотрудники штаба хранят информацию о пятнах в компьютере в виде матрицы размерностью M x N. Ячейка матрицы содержит 0, если нефтяное пятно в этих координатах отсутствует и 1, если есть (2 ≤ M, N ≤ 100). В матрице ячейки пятен не могут касаться друг к другу ни сторонами, ни углами.

Задание. Для облегчения ликвидации последствий аварии нужно написать программу OIL .*, которая будет находить общее количество пятен и количество пятен с одинаковой площадью.

Входные данные. Входной текстовый файл OIL.DAT содержит в первой строке два числа M и N, далее следуют M строк, в каждой по N целых чисел разделенных пробелами - элементы матрицы.

Исходные данные. Выходной текстовый файл OIL.SOL содержит в первой строке целое число k - общее количество пятен, далее в каждом из рядов содержится по два числа, первое - площадь пятна, второе - их количество. Данные сортировать по площадям в порядке возрастания.

Изображения задания, входного и выходного файлов можно увидеть, например, ЗДЕСЬ.

Это самая сложная задача в этой олимпиаде для 8-9 классов, не даром она оценена в 25 баллов. Тех знаний, которые вы получили в материалах этого блога на данный момент, на всю задачу, пожалуй, не хватит. Но кое-что мы найти могли.

Итак, начинаем с разбора условия.

Нам необходимо считать размер матрицы - двумерного массива, числа m и n. Поскольку известно, что (2 ≤ M, N ≤ 100), то наша матрица при объявлении переменных может быть заданна так:

Var

a:array[2..100,2..100] of integer;

Подробнее о матрицах можно почитать в предыдущих уроках - Матрица и Решение задач с матрицей

Так вот, матрица у нас заполнена 0 и 1, а значит, найдя сумму всех элементов матрицы, мы могли узнать общую площадь загрязнения.

ВОТ И НАПИШИТЕ с целью тренировки такую программку. Сами.

А трудность в решении поставленной задачи состоит в том, что необходимо с одной стороны посчитать каждую загрязненную клетку не саму по себе, а вместе с соседними загрязненными, и при этом ни одну из них не посчитать дважды.

Для того, чтоб полностью разобраться с решением задачи, я рекомендую ознакомиться с понятиями "Процедура" в языке Paskal, и "Рекурсия" в математике и программировании.







К следующей олимпиаде, которая будет через год, мы уже обязательно разберемся с этими понятиями. А пока можете посмотреть решение базовой задачи: "Разлив нефти"

четверг, 13 ноября 2014 г.

Задачи районной олимпиады по программированию. Разбор задачи 2.

Задача 2.

Разведчики получили шифрованную радиограмму. Для ее расшифровки надо знать специальный ключ, который они получили вместе с радиограммой отдельной строкой. Эта строка – набор произвольных символов, среди которых обязательно будут цифры. Для получения ключа найдите сумму цифр этой строки. Известно, что строка не длиннее 255 символов.

Входной файл – строка не длиннее 255 символов.

Выходной файл – ключ.

К чему сводится условие задачи? У нас есть строка символов. Читаем строку. Если символ совпадает с одной из цифр – добавляем его к сумме.

program Olimp_9_2;
var
i,sum:integer;
a:array[1..255] of char;
f,g:text;

begin
assign (f,'input.txt');
reset (f);

i:=1;                - счетчик элементов в массиве
sum:=0;              - начальное значение суммы

while not eof (f) do    - пока есть элементы в строке…

begin
read (f,a[i]);          - читаем элемент, загоняем его в массив

case a[i] of            - если элемент оказался цифрой – добавляем к сумме
'1': sum:=sum+1;
'2': sum:=sum+2;
'3': sum:=sum+3;
'4': sum:=sum+4;
'5': sum:=sum+5;
'6': sum:=sum+6;
'7': sum:=sum+7;
'8': sum:=sum+8;
'9': sum:=sum+9;

end;                  - оператор case не содержит begin, но заканчивается end;

i:=i+1;               - меняем счетчик на 1
end;

close (f);            - закрыли файл f

assign (g,'output.txt');
rewrite (g);
writeln (g,sum);
close (g);

end.

Вот и все...