Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Банк олимпиадных заданий.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
374.86 Кб
Скачать

Задача. Подземная дорога (поиск в ширину)

В некотором городе К-ске имеется свояподземная дорога. Администрация города решила построить новую кольцевую линию. "Центром" этого кольца должна стать одна из станций, при этом "радиус" такого кольца - минимальное кол-во станций, которое надо проехать, чтобы достичь кольцевой линии. То есть если радиус равен R - то кольцевая линия должна строиться на тех станциях, до которых можно добраться как минимум через R станций. Кольцо должно иметь как минимум две станции. Программа должна вывести все станции, через которые надо провести новую линию, или 0, если кольцо нельзяпостроить.

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

Первая строка содержит число N - количество станций метро (1<=N<=150) и число K. В следующих K строках содержится информация, описывающая схему. Сначала в строке идёт D - номер станции, затем число M, а далее - M чисел, которые показывают, с какими станциями соединена станция D.

В предпоследней строке - станция, которая будет "центром" станции, а в последней – радиус

кольца.

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

На экран вывести номера искомых станций (в любом порядке). Если кольцо нельзя построить -

вывести 0.

Пример:

input.txt

output.txt

9 5

3 3 1 4 6

2 2 1 4

7 2 1 9

5 3 1 8 6

4 2 8 9

1

1

2 3 5 7

Графическоепредставлениепримера:

Решение: при помощи поиска в ширину (BFS) на k-ой итерации цикла мы будем находить все станции, до которых можно добраться как минимум через k станций. Сделав ограничение по R и записывая "уровень" каждой станции, мы определим все такие станции.

Код программы:

constMaxN = 100;

typeMatrix = array[1..MaxN,1..MaxN] ofboolean; //типматрицысмежности. M[i,j] = true, если станции i и j соединены.

var

A : Matrix;

i, j, N, k, aa, bb, S, R, c: integer;

procedureBFS(A : Matrix; N, V, R : integer); //обход в ширину (V - корневаявершина)

vari, ps, pe : integer;

visited :array [1..MaxN] of boolean; //массивпосещённостивершинq : array [1..MaxN] of integer; //"очередь" вершин

ql :array [1..MaxN] of integer; //и ихуровней.

begin//в качестве списка очередных вершин будем использовать структуру "очередь"

ps := 1; //начало очереди

pe := 1; //конец очереди

q[pe] := v; //в очередь помещается исходная вершина. На каждом шаге в очередь будем заносить всех преемников данной вершины (назовём их 1-го уровня, т.е. до которых можно дойти напрямую). Затем просматриваем в очереди занесённые ранее вершины 1-го уровня и добавляем в конец очереди вершины 2-го уровня и так далее до опустошенияочереди.

visited[v] := TRUE; //вершина V посещена

ql[ps] := 0; //сама вершина - нулевой уровень

while(ps<= pe) and(ql[ps] <R) do//пока очередь не пуста или не достигли необходимого уровня R

begin

fori := 1 to ndo if (A[v, i]) and (not visited[i]) then

//перебираем все связные с V вершины

begin

inc(pe); //и добавляем в очередь q[pe] := i;

ql[pe] := ql[ps] + 1; //отмечаем новый уровень преемника.

visited[i] := true; //отмечаем вершину I пройденной

end;

inc(ps); //переходим к следующей вершине в очереди v := q[ps]; //и делаем её корневой

end;

while(ql[ps] = R) and(ps<= pe) do//после работы цикла в очереди останутся только вершины, имеющие уровень R и более.

begin

write(q[ps],' '); inc(ps);

end; end;

BEGIN

assign(input,'input.txt');

reset(input);

readln(input, N,c);

fori:=1 to c do begin

read(input, aa, k);

forj:=1 to k do begin

read(input, bb); A[aa, bb] :=true;

A[bb, aa] := true;

end; readln(input);

end;

readln(input, S); readln(input, R); close(input); BFS(A, N, S, R);

END.

Задача1

Для заданной строки символов проверить, является ли она симметричной или нет. (Симметричной считается строка, которая одинаково читается слева направо и справа налево). 

Проще всего в этой задаче определить длину строки n, организовать цикл по номеру символа в строке и сравнивать попарно первый символ с последним, второй - с предпоследним и т.д. Если хотя бы одна пара различна, то строка не симметричная. Так как просматривается сразу пара символов, то в цикле будет m = n div 2 повторений. Для запоминания результата просмотра введем переменную k (k будет равна 0, если строка симметрична и 1 иначе).  Программа, решающая эту задачу, будет иметь вид:

 

var s:string;

     i,k,n,m:integer;

begin

   readln(s);

   n:=length(s);

   k:=0;

   m:=n div 2;

   for i:=1 to m do

    if s[i]<>s[n-i+1] then k:=1;

   if k=0 then writeln('Строка симметрична')

           else writeln('Строка несимметрична');

end.

Задача 2

Для заданной строки символов вычислить произведение входящих в эту строку целых чисел (без учета их знаков). Например, для строки "kjjjkkj2.5jkjn,,,hfd45jgfvjlkfdii10,2hfhg" произведение 2*5*45*10*2=9000

Пусть s - строка. Обозначим длину строки - l. Организуем цикл, в котором будем проверять, является ли очередной символ цифрой, если да, то организуем новый цикл, в котором будем формировать строку sn, состоящую из цифр (очередное целое число). Потом преобразуем sn в число и вычислим произведение. Программа на Паскале, реализующая данный алгоритм, будет иметь следующий вид (переменная p в этой программе используется для накапливания значения произведения, переменная kod - для хранения кода результата преобразования строки в число):

 

var sn,s:string;     l,k,kod:integer;     v,p:real; begin writeln('Введите строку'); readln(s); l:=length(s); p:=1; k:=1; repeat   sn:='';   while (s[k]>='0')and(s[k]<='9')and(k<=l) do    begin     sn:=sn+s[k];     k:=k+1;    end;    if sn<>'' then    begin     val(sn,v,kod);     p:=p*v;    end;    k:=k+1;    until k>l;    writeln(' p=',p); end.

Задача 3

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

Имеется несколько путей решения этой задачи. Для упрощения предположим, что строка не начинается и не заканчивается пробелом и что между словами в строке стоит ровно по одному пробелу. Пусть известна пара слов, которую необходимо переставить, и - номера первой и последней букв в первом слове, и - номера первой и последней букв во втором слове. Рассмотрим способ, в котором для перестановки слов будем использовать следующий алгоритм:  Запишем буквы первого слова в обратном порядке (поменяв первую с последней, вторую с предпоследней и т.д.).  Например, из строки   получим dcba efghi.  Потом аналогичным образом переставим буквы второго слова:  из строки   получим dcba ihgfe.  Для получения окончательного результата необходимо записать буквы полученного словосочетания в обратном порядке:  Из строки   получим efghi abcd (что и требовалось получить).  Таким образом, для перестановки двух слов достаточно написать подпрограмму, которая меняет в заданной строке порядок букв на противоположный (инвертирует строку), и вызвать эту подпрограмму для первого слова, второго слова и всего словосочетания.  Обозначим invert(k,l) - процедуру, которая записывает в заданной строке s символы с k-того по l-й в обратном порядке, тогда программа, решающая задачу, будет иметь вид:

 

var s:string;     i,n,m1,m2,l1,l2:byte; procedure invert(k,l:byte); var i:byte;     ch:char; begin    for i:=k to ((l+k) div 2) do    begin       ch:=s[i];       s[i]:=s[l+k-i];       s[l+k-i]:=ch;    end; end; begin writeln('Введите строку'); readln(s); i:=0; n:=0; m1:=1;m2:=1;l1:=1;l2:=1; while i<length(s) do begin   i:=i+1;   if (s[i]=' ')or(i=length(s)) then   begin     n:=n+1;     if n=1 then     begin       m2:=i-1;       l1:=i+1     end     else     begin       n:=0;       if i=length(s) then l2:=i else l2:=i-1;       invert(m1,m2);invert(l1,l2);invert(m1,l2);       m1:=i+1     end   end end; writeln(s) end.

Лифт

Ограничения: время – 200мc, память - 64МБ

Петру необходимо попасть с этажа A на этаж B. Для вызова лифта на всех этажах офисного здания, кроме первого и последнего, есть две кнопки — для перемещения вниз и перемещения вверх. В тот момент, когда Петр нажал нужную кнопку вызова, лифт находился на этаже C и вез одного пассажира на этаж D. Если лифт проезжает мимо этажа, на котором нажата кнопка вызова, и лифт движется в подходящем направлении, то лифт останавливается, чтобы посадить дополнительного пассажира. Лифт перемещается между соседними этажами за одну единицу времени, также одну единицу времени занимает остановка лифта на этаже для высадки или посадки пассажиров.

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

Первая строка ввода содержит четыре целых числа A, B, C и D, разделенных одним пробелом (1 ≤ A, B, C, D ≤20, A≠B, C≠D, A≠C).

Вывести одно целое число — количество единиц времени от момента вызова лифта до момента, когда Петр выйдет из лифта на этаже B.

Пример ввода 1 Пример вывода 1

3 9 2 5 10

Пример ввода 2 Пример вывода 2

3 9 5 2 13

Пояснение к примеру 1

Лифт за 1 единицу времени доедет до 3-го этажа, остановится на 1 единицу времени, чтобы Петр сел в лифт, затем через 2 единицы времени доедет до 5-го этажа и остановится на 1 единицу времени для высадки предыдущего пассажира, через 4 единицы времени лифт довезет Петра до 9-го этажа, и через 1 единицу времени Петр выйдет из лифта.

Решение

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

Существует 4 варианта:

1) пассажир едет на этаж, где находится Петр;

2) Петр едет в том же направлении, что и лифт, и лифт может посадить его по пути, Петр выходит раньше или одновременно с пассажиром лифта;

3) тоже что и 2, но пассажир выходит раньше Петра;

4) лифт сначала отвозит пассажира, затем отвозит Петра.

Пример реализации:

uses math;

var a,b,c,d:integer;

begin

read(a,b,c,d);

if d=a then

writeln(abs(c-d)+1+abs(a-b)+1)

else if not((a<b)xor(c<d)) and (a>=min(c,d)) and (a<=max(c,d)) then

begin

if (b>=min(c,d)) and (b<=max(c,d)) then

writeln(abs(c-a)+1+abs(a-b)+1)

else

writeln(abs(c-a)+1+abs(a-d)+1+abs(d-b)+1);

end

else

writeln(abs(c-d)+1+abs(d-a)+1+abs(a-b)+1);

end.

Задача

Для любого целого числа N>7 найти все такие пары целых чисел x и y, что 3x+5y=N.

Разделим N нацело на 5 и получим k - максимальное значение для y (т.е. 0<=y<=k). Организуем цикл по переменной y , и будем рассматривать значения разности N-5y. Если это число делится нацело на 3, то полученное частное и есть соответствующее значение x.

Решение

var x,y,n,k:integer;

begin

writeln('Введите N');

readln(n);

k:=n div 5;

for y:=0 to k do

if (N-5*y) mod 3=0 then

begin

x:=(N-5*y) div 3;

writeln('x=',x,' y=',y);

end;

end.