Описание
Для введения и определения новых понятий будем использовать задачу из предыдущего урока, внеся некоторые изменения в ее условие, а именно:

  1. все входные данные будем вводить из текстового файла

  2. результат решения запишем (выведем) в текстовый файл

  3. расширим диапазон вводимых данных, для чего опишем и применим новый тип

Исходя из вышесказанного сформулируем условие задачи, введем новые термины и понятия, запишем ее решения в алгоритмической форме и на языке программирования Pascal, проведем тестирование программы


Задача
На листе бумаги изображен прямоугольник, размерами a×b квадратов. Некоторые N квадратов оказались закрашенными голубым цветом  (один из возможных вариантов приведен на рис.2). Напишите программу RECTANGL определяющую, какая часть прямоугольника (сколько квадратов) осталась незакрашенной

Формат входных данных
Входной файл RECTANGL.IN содержит в первой строке числа
a и b (1  a 1000) - количество квадратов по вертикали и горизонтали соответственно, а во второй - число N
(0 ≤  1000000) - количество закрашенных квадратов. Числа в строке разделены пробелом

Формат выходных данных

В выходной файл RECTANGL.OUT выведите единственное число - количество незакрашенных квадратов прямоугольника


Например:

RECTANGL.IN
3 5

5


RECTANGL.OUT
10





Идеи и комментарии

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


Чтение данных из входного файла

  • Для чтения данных из входного текстового файла необходимо знать его имя. Из условия задачи имеем: REGTANGL.IN

  • Свяжем это имя с некоторой переменной текстового типа, так как по условию файл текстовый. Пусть это будет переменная f. На языке Pascal это можно записать так:

    assign (f,'...');

    где assign - зарезервированное служебное слово, а вместо знака "..." (троеточие) записывается имя файла. В нашем случае имеем:

    assign (f,'rectangl.in');

  • Чтобы прочитать данные из файла, необходимо его открыть. Для этого используем процедуру reset(f). Обращаю ваше внимание, что в скобках указывается переменная, связанная с интересующим нас именем файла

  • Осуществим чтение данных из файла при помощи процедуры read (f,'...'), где вместо знака "..." (троеточие) указывается имя переменной или переменных (в последнем случае имена разделяются запятой), в которые мы хотим помещать данные из файла

  • После считывания всех данных завершим работу с файлом (говорят "закроем файл"), использовав для этой цели процедуру close(f)


Вернемся к условию задачи. Мы знаем, что входной файл содержит 2 строки: в первой записаны два числа, разделенные пробелом, а в третьей - одно. Следовательно, всего потребуется зарезервировать 3 ячейки памяти:

  • length_rectangle – длина прямоугольника - число квадратов по горизонтали

  • width_rectangle – ширина прямоугольника - число квадратов по вертикали

  • N – количество закрашенных квадратов (для удобства дадим имя, совпадающее с приведенным в условии задачи)


Для считывания длины и ширины прямоугольника (в квадратах) из первой строки входного файла достаточно простой языковой конструкции, о которой мы говорили выше:

readln (f,width_rectangle,length_rectangle);

т.е. в ячейки памяти width_rectangle и length_rectangle занесем значения a и b соответственно (обратите внимание на тот факт, что, например, значению а - количество квадратов по вертикали, соответствует переменная с именем width_rectangle - ширина прямоугольника, а не наоборот), а для считывания значения из второй строки достаточно записать:

read (f,N);


Замечание
Если вы были внимательны, то заметили, что для считывания данных из первой строки была применена процедура
readln, а для второй - read. Как уже было сказано на предыдущем уроке, такая запись связана с тем, что после завершения считывания данных из первой строки нам нужно будет переместить маркер (курсор) на вторую строку, чтобы прочитать число N. Эту операцию и выполняет процедура readln (считывает данные в позиции курсора, а затем переводит курсор в начало следующей строки). Для считывания данных со второй строки достаточно использовать процедуру read, т.к. после считывания мы подойдем к концу файла

 

Запись (вывод) данных выходной файл

  • Для вывода данных в выходной текстовый файл необходимо знать его имя. Из условия задачи имеем: REGTANGL.OUT

  • Свяжем это имя с некоторой переменной текстового типа, так как по условию файл текстовый. Пусть это будет переменная g. На языке Pascal это можно записать так:

    assign (g,'rectangl.out');

  • Чтобы записать данные в файл, необходимо его вначале создать. Для этого используем процедуру rewrite(g). Обращаю ваше внимание, что в скобках указывается переменная, связанная с интересующим нас именем файла

  • Осуществим запись (вывод) данных в файл при помощи процедуры write (g,'...'), где вместо знака "..." (троеточие) указывается имя переменной или переменных (в последнем случае имена должны разделяться запятой), значение которых мы хотим поместить в файл

  • После вывода данных завершим работу с файлом, т.е. закроем файл, использовав для этой цели процедуру close(g)


Вернемся к условию задачи. Мы знаем, что в выходной файл нужно вывести единственное число - количество незакрашенных квадратов, которое будем хранить в ячейке с именем
result – размер незакрашенной части прямоугольника. Исходя из сказанного, строка может иметь следующий вид:

write (g,result);

 

О типе данных
В предыдущей задаче мы имели небольшие значения ширины, длины и как следствие, количества закрашенных и незакрашенных квадратов - не более 15. Теперь же размеры прямоугольника могут быть значительно большими - до 1000
×1000=1000000=106 квадратов. Последняя запись (106) означает, что рассматривается число, у которого в записи есть 1 и справа шесть нулей, т.е. один миллион. Так записывать короче и мы будем часто использовать аналогичную запись

Следовательно, использовать переменные типа
shortint (короткое целое) в нашем случае недопустимо (напомню, что при использовании этого целочисленного типа наибольшее допустимо значение, помещаемое в соответствующую ячейку памяти, равно 127). По условию нашей задачи, наибольшее значение достигает 106. В языке программирования Pascal есть иные целочисленные типы, имеющие следующие граничные значения:

  • byte - допустимые значения [0..255]

  • word - допустимые значения [0..65535]

  • integer - допустимые значения [-32768..32767]

  • longint - допустимые значения [-2147483648..2147483647]


Замечание
Запись вида, например, [-3..5] означает, что рассматриваемое (у нас речь идет о целых числах) число может быть -3, -2, -1, 0, 1, 2, 3, 4, 5

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

  • ширина и длина прямоугольника могут выражаться целым числом от 1 до 1000, а значит, для хранения таких значений достаточен тип word

  • количества закрашенных или оставшихся незакрашенных квадратов могут быть значительно большими (могут ведь быть закрашенными (незакрашенными) все квадраты наибольшего из возможных прямоугольников), т.е. 106 квадратов. Для хранения таких числовых данных нужно использовать целочисленный тип longint

Осталось сделать последнее дополнение: в разделе описания переменных и их типов объявим переменные f и g как переменные типа text

 


Решение

Вначале обозначим решение задачи в алгоритмической форме:

нач нахождение размера неокрашенной части прямоугольника - 2;
      ввод width_rectangle, length_rectangle, N;
                  result:= length_rectangle*width_rectangle - N;
      вывод result
кон


Используя найденный алгоритм, запишем решение задачи на языке программирования Pascal:


{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}

program rectangle2;
 var length_rectangle,width_rectangle: word;
 N,result: longint;
 f,g: text;

Begin
{очистим используемые ячейки памяти}
 length_rectangle:=0; width_rectangle:=0; N:=0;
 result:=0;

{откроем доступ к входному и создадим выходной файлы}
 assign(f,'rectangl.in'); reset(f);
 assign(g,'rectangl.out'); rewrite(g);
  
{считываем входные данные и заносим их в соответствующие ячейки памяти}
 readln(f,width_rectangle,length_rectangle);
 read(f,N);

{сделаем необходимые вычисления и выведем результат в соответствующий файл}
 result:=width_rectangle*length_rectangle - N;
 write(g,result);

{завершим работу с файлами}
 close(f); close(g)
End.

Замечания
Как уже говорилось на первом уроке, если в задаче нет необходимости работать с клавиатурой и экраном для ввода/вывода информации, то не будем использовать соответствующие функции и процедуры работы с ними (такие, как например, ClrScr, Keypressed и др.), а также подключать дополнительные библиотеки (например Crt). Для избежания ошибок будем предварительно (в самом начале написания основного кода) очищать ячейки памяти от возможного "мусора". В нашем случае достаточно записать в каждую из них число "0". Применяя запись вида { ... } , где вместо "..." (троеточие) будем записывать необходимые нам комментарии, получим удобочитаемый код. Предлагаемый способ облегчает и ускоряет процесс написания программы, и при необходимости, ее правку


Тестирование
После окончания работы над программой выполним проверку ее общей работоспособности на приводимом тесте, обратив при этом внимание на результат (что вывела программа), который должен совпадать с приведенным, и формат вывода в соответствии с описанным в условии. После чего, для более полной оценки качества работы программы (выяснения, всегда ли программа дает при различных значениях
ab и N верный результат), необходимо использовать набор входных и соответствующих им выходных тестовых данных, специально созданный для проверки работоспособности программы. При этом нужно стараться всегда проверять как "средние" (промежуточные), так и "крайние" значения (ими в нашем случае будут значения ab (1 и 10000), N (0 и 1000000)


Один из возможных вариантов тестового набора приведем ниже:

номер теста

Входные данные (a и b)Входные данные (N)Выходные данные
11 101
218 4514796
3100 256144
4347 291104100873
5400 999578399022
61000 110000
714 100052778723
81000 786645681140319
91000 100010000000

 


© Практические занятия. Урок 2