Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

If not (p in podr) then begin




podr:= podr + [p]; { добавить к множеству }

count:= count + 1; { увеличить счетчик подразделений }

end;

end;

{ вывод результата }

av:= N / count;

writeln(av:0:2);

End.

По-видимому, это решение действительно наиболее эффективно в данной конкретной задаче. Однако, нужно помнить, что в других аналогичных задачах такой подход часто не работает из-за существенных ограничений множеств:

· число элементов множества не может быть больше 256;

· элементами множества могут быть только числа от 0 до 255;

· элементами множества не могут быть символьные коды, например, AB34a.

С учетом этого первое из рассмотренных решений является наиболее универсальным.

 

9) Эта задача имеет очень длинное условие, но решается довольно просто. Сначала нужно «вычленить» из условия и осознать существенные моменты:

· нужные нам участники получили наибольший балл (если нет победителей) или второй по величине (если победители есть); участники с более низкими баллами нас не интересуют;

· нам нужно хранить имя только одного из искомых участников, а не всех;

· класс нас не интересует.

Таким образом, для решения задачи при вводе исходных данных достаточно определить:

· количество участников, получивших высший балл, и имя одного из них;

· количество участников, получивших второй по величине балл, и имя одного из них;

Важно понять, что здесь не нужно заводить массивы для хранения всех имен и результатов в памяти; строго говоря, сделать это невозможно, потому что количество участников по условию не ограничено. Также не нужна никакая сортировка.

Для хранения данных заведем три целочисленных массива, каждый из которых состоит из двух элементов:

var ballBest: array[1..2] of integer; { результат (баллы) }

numBest: array[1..2] of integer; { количество }

nameBest: array[1..2] of string; { имена }

Первые элементы этих массивов относятся к тем, кто набрал наивысший балл, а вторые – к тем, кто набрал второй по величине балл.

Программа в целом выглядит так:

var ballBest: array[1..2] of integer;

numBest: array[1..2] of integer;

nameBest: array[1..2] of string;

N: integer; { число участников }

c: char; { символ для ввода }

i, j, k, ball: integer; { вспомогательные переменные }

name: string;

Begin

Readln(N); { ввод числа участников }

ballBest[1]:= -1; { начальное значение, < 0}

for i:=1 to N do begin

{ читаем фамилию и имя }

{ пропускаем класс }

{ читаем баллы участника }

{ обрабатываем баллы }

end;

{ определяем, есть ли победители }

{ выводим результат }

End.

Теперь последовательно рассмотрим все блоки, обозначенные комментариями. Начальное значение ballBest[1] должно быть меньше, чем самый низкий возможный результат, поэтому можно записать туда любое отрицательное число (так, чтобы у первого же участника был результат больше). Для остальных элементов массивов начальные значения не нужны.

Чтение фамилии и имени в символьную строку name мы уже рассматривали ранее:

name:= '';

for j:=1 to 2 do

Repeat

read(c);

name:= name + c;

until c = ' ';

Пропуск класса также выполняется стандартно:

read(k);

Дальше читаем результат участника (баллы) – чтение до конца строки:

readln(ball);

Что делать с этими баллами? Нас интересуют 4 варианта, при которых изменяются массивы ballBest, numBest и nameBest, определяющие результат:

· ball > ballBest[1], новый участник набрал больше баллов, чем все предыдущие; в этом случае надо скопировать все 1-ые элементы массивов во 2-ые, а затем в 1-ые записать данные нового участника (имя, баллы, количество = 1);

· ball = ballBest[1], новый участник набрал столько же баллов, сколько лучшие из предыдущих; нужно увеличить их количество на 1;

· ballBest[2] < ball < ballBest[1], новый участник набрал «второе» количество баллов; нужно во 2-ые элементы массивов записать данные нового участника (имя, баллы, количество = 1);

· ball = ballBest[2], новый участник набрал столько же баллов, сколько участники с вторым известным ранее результатом; нужно увеличить их количество на 1.

Остальные варианты (когда ball < ballBest[2]) нас не волнуют, потому что они не влияют на результат. Ниже приведен блок обработки прочитанного количества баллов нового участника. Обратите внимание, что каждый новый if вложен в блок else предыдущего условного оператора. Подумайте, почему это необходимо.

if ball > ballBest[1] then begin

ballBest[2]:= ballBest[1];

numBest[2]:= numBest[1];

nameBest[2]:= nameBest[1];

ballBest[1]:= ball;

numBest[1]:= 1;

nameBest[1]:= name;

End

Else

if ball = ballBest[1] then

numBest[1]:= numBest[1] + 1

Else

if ball > ballBest[2] then begin

ballBest[2]:= ball;

numBest[2]:= 1;

nameBest[2]:= name;

End

Else

if ball = ballBest[2] then

numBest[2]:= numBest[2] + 1;

Теперь определим есть ли победители, то есть, верно ли, что ballBest[1] > 200 и numBest[1] не превышает 20% от N. Если эти два условия верны одновременно, победители есть, и для ответа нужно использовать вторые элементы массивов (запишем в переменную i значение 2), иначе – первые.

if (ballBest[1] > 200) and (numBest[1]*100 <= N*20) then

i:= 2

else i:= 1;

Обратите внимание, что во втором условии используется отношение «меньше или равно» (нестрогое равенство). Кроме того, определение доли 20% сведено к операциям только с целыми числами! Вариант numBest[1]<=N*0.2 хуже, потому что выражение в правой части неравенства – вещественное, а большинство вещественных чисел (в том числе, 0,2) невозможно точно представить в памяти (они представляют собой бесконечную дробь).

Остается вывести результат на экран. Если искомых участников больше 1, выводим их количество numBest[i ], иначе – имя единственного участника nameBest[i].

if numBest[i] > 1 then

writeln(numBest[i])

else writeln(nameBest[i]);

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

var Best: array[1..2] of record

ball: integer;

num: integer;

name: string;

end;

N: integer;

c: char;

i, j, k, ball: integer;

name: string;

Begin

Readln(N);

Best[1].ball:= -1;

for i:=1 to N do begin

name:= '';

for j:=1 to 2 do

Repeat

Read(c);

name:= name + c;

until c = ' ';

Readln(k, ball);

if ball > Best[1].ball then begin

Best[2]:= Best[1];

Best[1].ball:= ball;

Best[1].num:= 1;

Best[1].name:= name;

End

Else

if ball = Best[1].ball then

Best[1].num:= Best[1].num + 1

Else

if ball > Best[2].ball then begin

Best[2].ball:= ball;

Best[2].num:= 1;

Best[2].name:= name;

End

Else

if ball = Best[2].ball then

Best[2].num:= Best[2].num + 1

end;

if (Best[1].ball > 200) and

(Best[1].num*100 <= N*20) then

i:= 2

else i:= 1;

if Best[i].num > 1 then

writeln(Best[i].num)

else writeln(Best[i].name);

End.

 

10) Прежде всего, нужно понять, что «магазин» определяется сочетанием «Фирма + Улица». Каждый магазин может продавать сметану разных сортов, каждому сорту соответствует своя строчка в исходных данных. Важно, что нам НЕ нужно запоминать ни фирму, ни улицу, поэтому при чтении их можно вообще пропускать.

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

var MinPrice, Count: array[1..3] of integer;

Для поиска минимальных элементов нужно записать начальные значения: в каждый элемент массива MinPrice – любую цену, больше максимально возможной, а все счетчики обнулить.

for i:=1 to 3 do begin

MinPrice[i]:= 5001; { любое число > 5000 }

Count[i]:= 0; { обнулить счетчики }

end;

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

15 →1, 20 →2, 25 →3

Оказывается, это сделать достаточно просто, код рассчитывается по формуле

K div 5 - 2

Как эту формулу получить? Мы видим, что при увеличении k на 5 код увеличивается на 1, поэтому мы имеем дело с линейной зависимостью с коэффициентом 1/5:

код = k div 5 + b

Свободный член b подбирается, например, из условия 15div5+b=1 (при k=15 мы должны получить код 1). Тогда 3+b=1 и b=-2.

Если в какой-то задаче числа совсем «нескладные» и не удается вывести формулу, можно использовать оператор выбора (case) или серию условных операторов. Никаких других хитростей в программе нет:

program milk;

var MinPrice, Count: array[1..3] of integer;

N: integer;

c: char;

i, j, k, price: integer;

Begin

Readln(N);

for i:=1 to 3 do begin

MinPrice[i]:= 5001;

Count[i]:= 0;

end;

for i:=1 to N do begin

for j:=1 to 2 do { пропускаем фирму и улицу }

repeat read(c); until c = ' ';

readln(k, price); { читаем жирность и цену }

k:= k div 5 - 2; { получаем код – номер в массивах }

if price < MinPrice[k] then begin

MinPrice[k]:= price;

Count[k]:= 1;

End

Else

if price = MinPrice[k] then

Count[k]:= Count[k] + 1;

end;

for k:=1 to 3 do

write(Count[k], ' ');

End.

11) Определимся с данными, которые фактически влияют на результат:

· нас интересует только количество участников, их нужно разделить по классам и по баллам

· нас не интересуют имена и фамилии, поэтому при чтении их можно пропускать

Мы будем использовать два массива: в массиве Total будем хранить общее количество участников с разбивкой по баллам (в элементе Total[i] хранится количество участников, получивших ровно i баллов), а в двухмерном массиве Count – количество участников с разбивкой по баллам и классам, то есть, Count[i,j] хранит количество участников из класса j, которые получили ровно i баллов[1]:

const MAX = 70;

var Total: array[0..MAX] of integer;

Count: array[0..MAX,7..11] of integer;

В начале программы оба массива нужно обнулить[2].

for ball:=0 to MAX do begin

Total[ball]:= 0;

for class:=7 to 11 do Count[ball,class]:= 0;

end;

Таким образом, «скелет» программы можно записать так:

const MAX = 70;

var Count: array[0..MAX,7..11] of integer;

Total: array[0..MAX] of integer;

N: integer;

c: char;

i, j, class, ball, minBall, Sum: integer;

Begin

Readln(N);

for ball:=0 to MAX do begin

Total[ball]:= 0;

for class:=7 to 11 do Count[ball,class]:= 0;

end;

for i:=1 to N do begin

{ пропустить фамилию и имя }

{ прочитать класс и баллы }

{ увеличить счетчики }

end;

{ определить <=25% призеров и их минимальный балл }

{ если получилось <25%, проверить следующих }

{ вывести минимальный балл }

{ количество призеров по классам }

End.

Теперь расшифруем все блоки, обозначенные комментариями. При чтении пропускаем фамилию и имя:

for j:=1 to 2 do

repeat read(c); until c = ' ';

затем считываем класс и баллы (readln, до конца строки)

readln(class, ball);

и увеличиваем общий счетчик и счетчик для данного класса:

Total[ball]:= Total[ball] + 1;

Count[ball,class]:= Count[ball,class] + 1;

Теперь определяем всех, кто гарантированно попадает в призеры. Накапливаем количество призеров, начиная с максимально возможного количества баллов, пока сумма укладывается в 25%:

Sum:= 0;

ball:= MAX;

while (Sum+Total[ball])*100 <= 25*N do begin

Sum:= Sum + Total[ball];

if Total[ball] > 0 then minBall:= ball;

ball:= ball - 1;

end;

Здесь нужно обратить внимание на два момента. Во-первых, для проверки на 25% используется нестрогое неравенство, и все операции выполняются с целым числами. Во-вторых, новое значение записывается в переменную minBall только тогда, когда количество участников, набравших этот балл, не ноль (по условию нужно вывести минимальный балл, который был фактически набран).

На следующем шаге проверяем участников «на границе».

if ((Sum+1)*100 <= 25*N) and (ball*2 > MAX) then

minBall:= ball;

Условие

(Sum+1)*100 <= 25*N

означает, что по крайней мере еще один участник «вписывается» в 25% лучших, а условие

ball*2 > MAX

говорит о том, что он набрал больше половины от максимального количества баллов.

Теперь можно вывести минимальный балл призеров:

writeln(minBall);

Чтобы вывести количество призеров по параллелям, мы сначала для каждого суммируем количество участников, набравших от minBall до MAX баллов:

for class:=7 to 11 do begin

Sum:= 0;

for ball:=minBall to MAX do

Sum:= Sum + Count[ball,class];

write(Sum, ' ');

end;

 

12) В этой задаче решение можно разбить на два этапа:

· прочитать данные и запомнить имена и фамилии тех, кто не прошел тестирование;

· отсортировать список по алфавиту и вывести на экран

Количество участников ограничено (не более 500), это косвенно говорит о том, что нужно использовать массив для хранения результатов. Для сортировки надо одновременно удерживать в памяти все данные, поэтому без массива символьных строк здесь не обойтись:

var List: array[1..500] of string;

Структура программы:

var List: array[1..500] of string;

name, temp: string;

c: char;

i, j, N, ball1, ball2, count: integer;

Begin

count:= 0; { счетчик несдавших }

readln(N);

for i:=1 to N do begin

{ прочитать фамилию и имя }

{ прочитать баллы }

{ если не сдал, запомнить }

end;

{ сортировка по алфавиту }

{ вывод списка }

End.

Расшифруем отдельные блоки, обозначенные комментариями. В цикле сначала читаем фамилию и имя очередного абитуриента и записываем их в переменную name:

name:= '';

for j:=1 to 2 do

Repeat

read(c);

name:= name + c;

until c = ' ';

Далее читаем две оценки в переменные ball1 и ball2, используя оператор readln (чтение до конца строки).

readln(ball1, ball2);

Если абитуриент не прошел тестирование, увеличиваем счетчик count и записываем его фамилию и имя в очередной элемент списка:

if (ball1 < 30) or (ball2 < 30) then begin

count:= count + 1;

List[count]:= name;

end;

Предполагая, что коды русских букв стоят по алфавиту, после ввода данных применим сортировку, например, так:

for i:=1 to count-1 do

for j:=i to count do

if List[i] > List[j] then begin

temp:= List[i];

List[i]:= List[j];

List[j]:= temp;

end;

Заметьте, что в сортировке участвуют не все 500 элементов массива List, а только count – столько абитуриентов не прошли тестирование. Остается вывести список на экран:

for i:=1 to count do writeln(List[i]);

Вот полная программа:

var List: array[1..500] of string;

name, temp: string;

c: char;

i, j, N, ball1, ball2, count: integer;

Begin

count:= 0;

readln(N);

for i:=1 to N do begin

name:= '';

for j:=1 to 2 do

Repeat

read(c);

name:= name + c;

until c = ' ';

readln(ball1, ball2);

if (ball1 < 30) or (ball2 < 30) then begin

count:= count + 1;

List[count]:= name;

end;

end;

for i:=1 to count-1 do

for j:=i to count do

if List[i] > List[j] then begin

temp:= List[i];

List[i]:= List[j];

List[j]:= temp;

end;

for i:=1 to count do writeln(List[i]);

End.

 

13) Эта задача – полный аналог задачи 10. Прежде всего, нужно понять, что «АЗС» определяется сочетанием «Фирма + Улица». Каждая АЗС может продавать бензин разных сортов, каждому сорту соответствует своя строчка в исходных данных. Важно, что нам НЕ нужно запоминать ни фирму, ни улицу, поэтому при чтении их можно вообще пропускать.

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

var MinPrice, Count: array[1..3] of integer;

Для поиска минимальных элементов нужно записать начальные значения: в каждый элемент массива MinPrice – любую цену, больше максимально возможной, а все счетчики обнулить.

for i:=1 to 3 do begin

MinPrice[i]:= 3001; { любое число > 3000 }

Count[i]:= 0; { обнулить счетчики }

end;

Дальше возникает следующий вопрос: как, прочитав из файла марку бензина k, рассчитать номер соответствующего элемента массива (код):

92 →1, 95 →2, 98 →3

Так же, как и в задаче 10, замечаем, что при увеличении k на 3 код увеличивается на 1, то есть, мы получаем линейную зависимость с коэффициентом 1/3. Свободный член находим из условия 92 div 3 + b = 1, что дает b = -2 9, так что

код = k div 3 - 29

Если в какой-то задаче числа совсем «нескладные» и не удается вывести формулу, можно использовать оператор выбора (case) или серию условных операторов. Никаких других хитростей в программе нет[3]:

program gasoline;

var MinPrice, Count: array[1..3] of integer;

N: integer;

c: char;

i, j, k, price: integer;

Begin

Readln(N);

for i:=1 to 3 do begin

MinPrice[i]:= 3001;

Count[i]:= 0;

end;

for i:=1 to N do begin

for j:=1 to 2 do { пропускаем фирму и улицу }

repeat read(c); until c = ' ';

readln(k, price); { читаем марку бензина и цену }

k:= k div 3 - 29; { получаем код – номер в массивах }

if price < MinPrice[k] then begin

MinPrice[k]:= price;

Count[k]:= 1;

End

Else

if price = MinPrice[k] then

Count[k]:= Count[k] + 1;

end;

for k:=1 to 3 do

write(Count[k], ' ');

End.

 

14) В этой задаче нужно подсчитать, сколько раз встречается каждая буква. Если из букв можно составить палиндром, то одна буква (центральная) может встречаться нечетное число раз, а остальные – обязательно четное.

Для подсчета количества букв (в английском языке всего 26 букв) можно использовать массив

var count: array[1..26] of integer;

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

var count: array['A'..'Z'] of integer;

Перед началом работы нужно заполнить его нулями (ни одного символа еще не получено):

for c:='A' to 'Z' do count[c]:= 0;

Ввод символов (до точки) естественно делать в цикле while:

read(c);

while c <> '.' do begin

count[c]:= count[c] + 1;

read(c);

end;

Обратите внимание, что в такая конструкция 1) правильно обрабатывает ситуацию, когда первый символ – это точка; 2) не теряет символ, стоящий перед точкой. А вот эти два варианта – неправильные (разберитесь, почему?):

repeat read(c); count[c]:=count[c]+1; until c = '.';   while c <> '.' do begin count[c]:=count[c]+1; read(c); end;

Теперь считаем, сколько символов встречаются нечетное число раз. Здесь nOdd – целая переменная, а cOdd – символьная переменная, куда мы записываем центральный символ.

nOdd:= 0;

for c:='A' to 'Z' do

if count[c] mod 2 = 1 then begin

cOdd:= c;

Inc(nOdd);

end;

Если нашли нечетное количество таких символов, то палиндром составить нельзя:

if nOdd > 1 then

Writeln('Нет')

Else begin

writeln('Да');

{ можно составить! }

end;

Остается разобраться, как вывести палиндром в алфавитном порядке. Сначала проходим весь массив count и выводим каждую букву в «половинном» количестве (вторая половина будем справа от центра!):

for c:='A' to 'Z' do

for i:=1 to count[c] div 2 do

write(c);

Обратите внимание, что буква, стоящая по центру, тут тоже может появиться, если она встречается более одного раза.

Затем выводим центральный символ, если он есть:

if nOdd = 1 then write(cOdd);

и оставшийся «хвост», уже в обратном порядке, от 'Z' до 'A':

for c:='Z' downto 'A' do

for i:=1 to count[c] div 2 do

write(c);

Вот полная программа:

var count: array['A'..'Z'] of integer;

i, nOdd: integer;

c, cOdd: char;

Begin

for c:='A' to 'Z' do count[c]:= 0;

read(c);

while c <> '.' do begin

count[c]:= count[c] + 1;

read(c);

end;

nOdd:= 0;

for c:='A' to 'Z' do

if count[c] mod 2 = 1 then begin

cOdd:= c;

Inc(nOdd);

end;

if nOdd > 1 then

Writeln('Нет')

Else begin

writeln('Да');

for c:='A' to 'Z' do

for i:=1 to count[c] div 2 do

write(c);

if nOdd = 1 then write(cOdd);

for c:='Z' downto 'A' do

for i:=1 to count[c] div 2 do

write(c);

end;

End.

15) Для решения задачи нужно ответить на ряд вопросов:

Какие данные нужно хранить?

Какие структуры данных применить (простые переменные, массив, запись и т.п.)?

Как читать данные?

Какую обработку можно выполнить прямо при чтении?

Какую обработку нужно выполнить после чтения всех данных?

Как выводить результаты?

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

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

type TInfo = record

name: string[33];

sum: integer;

end;

Поле name хранит имя и фамилию как одну символьную строку, ее длина равна сумме максимальных длин имени и фамилии (12 + 20) плюс 1 символ на пробел между ними. Второе поле – сумма баллов, ее мы будем считать прямо во время чтения данных. Уже можно написать начало программы:

var Info: array[1..1000] of TInfo;

M, N, i, j, ball: integer;

c: char;

Begin

readln(N); { число спортсменов }

readln(M); { число видов многоборья }

for i:=1 to N do begin

Info[i].name:= '';

for j:=1 to 2 do { читаем два блока: фамилию и имя }

Repeat

read(c);

Info[i].name:= Info[i].name + c;

until c = ' ';

{ здесь нужно читать баллы и суммировать их }

end;

{ сортировка массива }

{ вывод таблицы результатов }

End.

Чтение и суммирование баллов по отдельным видам спорта (их всего M) выполняем в цикле:

Info[i].sum:= 0;

for j:=1 to M do begin

read(ball);

Info[i].sum:= Info[i].sum + ball;

end;

При сортировке массива нам потребуется переставлять структуры типа TInfo, поэтому нужно объявить вспомогательную структуру:

var temp: TInfo;

Для сортировки можно использовать любой метод, например, классический «метод пузырька»:

for i:=1 to N-1 do

for j:=N-1 downto i do

if Info[j].sum < Info[j+1].sum then begin

temp:= Info[j];

Info[j]:= Info[j+1];

Info[j+1]:= temp;

end;

Осталось решить вопрос о выводе данных. Итак, список спортсменов отсортирован по убыванию суммы баллов, но места не расставлены. Сложность в том, что несколько спортсменов могут набрать одинаковую сумму, при этом они должны получить одно и то же место.

Сделаем вывод места следующим образом. Введем целую переменную mesto. Очевидно, что тот, кто стоит первым в списке, занял первое место (запишем в переменную mesto значение 1). Теперь в цикле рассмотрим всех спортсменов, стоящих в списке под номерами от 1 до N. Если номер очередного спортсмена больше 1 и его сумма баллов меньше сумме балов предыдущего, то увеличиваем переменную mesto на 1. Затем выводим фамилию и имя, сумму баллов и mesto.

mesto:= 1;

for i:=1 to N do begin

if (i > 1) and (Info[i].sum < Info[i-1].sum) then

mesto:= mesto + 1;

writeln(Info[i].name, ' ', Info[i].sum, ' ', mesto);

end;

Вот вся программа целиком:

type TInfo = record

name: string[33];

sum: integer;

end;

var Info: array[1..1000] of TInfo;

M, N, i, j, ball, mesto: integer;

c: char;

temp: TInfo;

Begin

readln(N); { число спортсменов }

readln(M); { число видов многоборья }

for i:=1 to N do begin

Info[i].name:= '';

for j:=1 to 2 do { читаем два блока: фамилию и имя }

Repeat

read(c);

Info[i].name:= Info[i].name + c;

until c = ' ';

{ читаем баллы и суммируем их }

Info[i].sum:= 0;

for j:=1 to M do begin

read(ball);

Info[i].sum:= Info[i].sum + ball;

end;

end;

{ сортировка массива }

for i:=1 to N-1 do

for j:=N-1 downto i do

if Info[j].sum < Info[j+1].sum then begin

temp:= Info[j];

Info[j]:= Info[j+1];

Info[j+1]:= temp;

end;

{ вывод таблицы результатов }

mesto:= 1;

for i:=1 to N do begin

if (i > 1) and (Info[i].sum < Info[i-1].sum) then

mesto:= mesto + 1;

writeln(Info[i].name, ' ', Info[i].sum, ' ', mesto);

end;

End.

 

16) В этой задаче используются данные типа «время», которые вводятся в символьном виде. Работать с ними в таком формате (например, сравнивать) неудобно, потому нужно переводить время в числовую форму, например, в число минут от 00:00. Так время 09:45 преобразуется в число 60*9+45=585.

Поскольку эта операция выполняется неоднократно в разных местах программы (сначала ввод текущего времени в первой строке, а потом – ввод времени освобождения ячейки для каждого пассажира), удобно написать функцию, которая преобразует символьную строку в формате hh:mm (hh обозначает часы, а mm – минуты) в целое число так, как рассказано выше. Вот пример такой функции:

function Time2Int(sTime: string): integer;

var h, m, code0: integer;

Begin

code0:= Ord('0');

h:= 10*(Ord(sTime[1])-code0) + (Ord(sTime[2])-code0);

m:= 10*(Ord(sTime[4])-code0) + (Ord(sTime[5])-code0);

Time2Int:= 60*h + m;

end;

Здесь в переменную code0 мы записываем код символа '0', чтобы не вычислять его повторно.

В условии сказано, что число пассажиров в списке не превышает 1000, это явное указание на то, что нужно прочитать данные в массив записей примерно такой структуры:

type TInfo = record

name: string[20]; { фамилия }

time: integer; { время освобождения ячейки }

end;

Сам массив мы объявим так:

var Info: array[1..1000] of TInfo;

Сложность заключается в том, что нам нужно записывать в массив информацию только о тех пассажирах, для которых время освобождения ячейки не больше, чем curTime+120, где curTime – текущее время. Все остальные строки нужно игнорировать. Это значит, что требуется ввести счетчик count (целую переменную), в которой мы будем хранить количество «хороших» пассажиров, которые освободят свои ячейки не более, чем через 2 часа (120 минут). Получается такой цикл ввода:

count:= 0;

for i:=1 to N do begin

... { здесь ввести данные в Info[count+1] }

if Info[count+1].time <= curTime+120 then

count:= count + 1;

end;

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

Как вводить данные? Хотя все официальные рекомендации по решению задачи С4 основаны на посимвольном вводе данных, многие профессионалы предпочитают сначала прочитать всю очередную строку в символьную переменную s, а потом «разбирать» ее в памяти. В данном случае такой подход позволяет значительно упростить программу, и мы его применим (для разнообразия).

Будем вводить строку s целиком, искать пробел и делить ее на две части (слева от пробела – фамилия, справа – время). Затем время преобразуем в целое число с помощью уже написанной функции Time2Int:

for i:=1 to N do begin

readln(s);

p:= Pos(' ', s);

Info[count+1].name:= Copy(s,1,p-1);

Info[count+1].time:= Time2Int(Copy(s,p+1,Length(s)-p));

if Info[count+1].time <= curTime+120 then

count:= count + 1;

end;

Теперь остается только отсортировать массив и вывести список фамилий в нужном порядке. Важно не забыть, что нужно сортировать не N элементов, а count (именно столько мы нашли «хороших» пассажиров):

for i:=1 to count do

for j:=count-1 downto i do

if Info[j].time > Info[j+1].time then begin

temp:= Info[j];

Info[j]:= Info[j+1];

Info[j+1]:= temp;

end;

Вот полная программа:

type TInfo = record

name: string[20];

time: integer;

end;

var Info: array[1..1000] of TInfo;

s: string;

N, p, i, j, count, curTime: integer;

c: char;

temp: TInfo;

{ функция для преобразования времени в число }

function Time2Int(sTime: string): integer;

var h, m, code0: integer;

Begin

code0:= Ord('0');

h:= 10*(Ord(sTime[1])-code0) + (Ord(sTime[2])-code0);

m:= 10*(Ord(sTime[4])-code0) + (Ord(sTime[5])-code0);

Time2Int:= 60*h + m;

end;

{--------------------------------------------}

Begin

readln(s);

curTime:= Time2Int(s);

readln(N);

count:= 0;

{ ввод данных о пассажирах }

for i:=1 to N do begin

readln(s);

p:= Pos(' ', s);

Info[count+1].name:= Copy(s,1,p-1);

Info[count+1].time:= Time2Int(Copy(s,p+1,Length(s)-p));

if Info[count+1].time <= curTime+120 then

count:= count + 1;

end;

{ сортировка массива }

for i:=1 to count do

for j:=count-1 downto i do

if Info[j].time > Info[j+1].time then begin

temp:= Info[j];

Info[j]:= Info[j+1];

Info[j+1]:= temp;

end;

{ вывод списка }

for i:=1 to count do

writeln(Info[i].name);

End.

17) условия становится ясно, что задача решается в два этапа:

I. прочитать символы до точки и определить длину самого короткого слова из латинских букв (обозначим ее minLen);

II. сделать «сдвиг» кодов латинских букв на minLen влево.

Начнем с первого. Простое посимвольное чтение строки s до первой встреченной точки выглядит так (здесь c – переменная типа char):

s:= ''; { пустая строка }

Repeat

read(c); { прочитали символ }

s:= s + c; { добавили в конец строки }

until c = '.';

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

Как определить, что прочитанный символ – латинская буква? Конечно, можно использовать условный оператор со сложным условием:

if (('a' <= c) and (c <= 'z')) or

(('A' <= c) and (c <= 'Z')) then...

Более красиво это можно сделать с помощью оператора in, который проверяет, входит ли элемент во множество:

if c in ['a'..'z', 'A'..'Z'] then...

Здесь множество в квадратных скобках содержит два интервала: от 'a' до 'z' и от 'A' до 'Z'.

Если очередной прочитанный символ – латинская буква, нужно увеличить len на единицу (слово продолжается). Если же это не латинская буква, то слово закончилось, так как встречен символ-разделитель. Если в переменной len ненулевое значение, нужно сравнить эту длину с минимальной и, если прочитанное слово короче всех предыдущих, записать его длину в minLen. Таким образом, цикл ввода выглядит так:

s:= '';

minLen:= 201; { любое число > 200 }

len:= 0;

Repeat

read(c);

s:= s + c;

if c in['a'..'z','A'..'Z'] then

len:= len + 1

Else begin

if (len > 0) and (len < minLen) then

minLen:= len;

len:= 0;

end;

until c = '.';

Теперь нужно в цикле пройти всю прочитанную строку и «сдвинуть» каждый символ (точнее, его код) вправо на minLen:

for i:=1 to Length(s) do

if s[i] in ['a'..'z','A'..'Z'] then begin

code:= Ord(s[i]); { старый код }

k:= code - minLen; { новый код }

s[i]:= Chr(k);

end;

Однако такое решение не учитывает цикличность: например, при сдвиге буквы 'A' на 2 символа влево мы не получим 'Y'. Поэтому после изменения кода нужно проверить, не вышел ли он за допустимые границы (диапазона латинских букв), а если вышел, то добавить к полученному коду 26 (число латинских букв), что обеспечит циклический сдвиг:

k:= code - minLen; { новый код }

{ цикличность }

if s[i] in ['a'..'z'] then

if k < Ord('a') then k:= k + 26;

if s[i] in ['A'..'Z'] then

if k < Ord('A') then k:= k + 26;

Вот полная программа:

var c: char;

s: string;

len, minLen, code, i, k: integer;

Begin

s:= '';

minLen:= 201; { любое число > 200 }

len:= 0;

{ чтение данных }

Repeat

read(c);

s:= s + c;

if c in['a'..'z','A'..'Z'] then

len:= len + 1

Else begin

if (len > 0) and (len < minLen) then

minLen:= len;

len:= 0;

end;

until c = '.';

{ сдвиг кодов на minLen влево }

for i:=1 to Length(s) do

if s[i] in ['a'..'z','A'..'Z'] then begin

code:= Ord(s[i]); { старый код }

k:= code - minLen; { новый код }

{ цикличность }

if s[i] in ['a'..'z'] then

if k < Ord('a') then k:= k + 26;

if s[i] in ['A'..'Z'] then

if k < Ord('A') then k:= k + 26;

{ запись нового кода }

s[i]:= Chr(k);

end;

writeln(s);

End.

 

18) В условии очень важна последняя строчка: «количество голосов избирателей в исходном списке может быть велико (свыше 1000), а количество различных партий в этом списке не превосходит 10». Это значит, что

· нельзя хранить в массиве все прочитанные записи

· можно (и нужно) хранить в массиве названия партий, их не больше 10.

Таким образом, нужно выделить массив строк:

const MAX = 10;

var Names: array[1..MAX] of string;

Поскольку нужно считать, сколько голосов получила каждая парт

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...