Задачи, сгруппированные по методам решения. Использование дополнительного массива "флажков" (три задачи - один алгоритм)
Рассмотрим несколько практических задач.
Задача 1: В строке, содержащей арифметическое выражение проверить, правильно ли расставлены скобки. В случае лишних скобок - не считать неправильным расстановку скобок (например: ((а+в)) -скобки расставлены верно).
Идея решения:
- Допустим, дано арифметическое выражение: (а + в ((4а - 8) в + 3) - 15в)
-
Резервируем два массива: А$ и Flag. "Разбираем" строку, в которой хранится арифметическое выражение (применив типовой алгоритм "РАЗБОРА" СТРОКИ НА СИМВОЛЫ), помещая каждый символ в элемент массива А$.
Массив Flag заполняем флажками:
- "1" - если элемент массива А$ - открывающаяся скобка;
- "-1" - если элемент массива А$ - закрывающаяся скобка (рис. 7.1).
-
Суммируем элементы массива Flag. Если в процессе перебора элементов сумма станет отрицательной, значит скобки расставлены неверно. Итоговая сумма должна быть равна 0.
Решение задачи на Бейсике:
input "введите ар. выражение"; stroka$ n=len(stroka$) dim a$ (n), flag (n) rem- for i=1 to n a$(i)=mid$(stroka$, i, 1) next rem======================= for i=1 to n if a$(i)='(' then flag (i)=1 if a$(i)=')' then flag (i)=-1 next rem======================= for i=1 to n s=s+flag (i) if s<0 then x=1 next if s=0 and x=0 then ?"скобки расставлены верно" else ?"скобки расставлены неверно"
Решение задачи на Паскале:
const m=10; var flag: array [1..m] of integer; a: array [1..m] of string[1]; stroka: string; i,s,n,x: integer; begin writeln ('введите ар. выражение'); readln (stroka); n:=length (stroka); for i:=1 to n do begin a[i]:=copy(stroka, i, 1); flag[i]:=0; end; for i:=1 to n do begin if a[i]="(" then flag [i]:=1; if a[i]=")" then flag [i]:=-1; end; s:=0; for i:=1 to n do begin s:=s+flag [i]; if s<0 then x:=1; end; if (s=0) and (x=0) then writeln ('скобки расставлены верно') else writeln ('скобки расставлены неверно'); end.
Тест:
Задача 2: В картинной галерее работают сторожа. Для каждого сторожа известно время прихода на работу и время ухода. Определить, всегда ли галерея охраняется.
Идея решения:Пример (табл. 7.1):
Время прихода | Время ухода | |
---|---|---|
1 сторож | 8.00 | 12.00 |
2 сторож | 11.00 | 16.00 |
3 сторож | 15.00 | 19.30 |
4 сторож | 20.00 | 23.50 |
-
Заполняем массивы:
А: временем прихода и ухода сторожей;
Flag:
- "1" - если соответствующий элемент массива А - время прихода сторожа;
- "-1" - если элемент массива А - время ухода сторожа;
-
СОРТИРУЕМ массив А, одновременно переставляя элементы массива flag:
-
Суммируем элементы второго массива. Если текущая сумма обнулилась (но конец массива не достигнут), то, значит, галерея осталась без охраны (в 19.30 сторож ушел, а смена еще не пришла).
Решение на Бейсике:
input "количество сторожей="; n dim a(2*n), flag(2*n) for i=1 to n*2 step 2 input "время прихода="; a(i) flag (i) = 1 input "время ухода="; a(i + 1) flag (i + 1) = -1 next rem==сортировка======================================= for j = 2*n to 2 step -1 for i = 1 to j - 1 if a(i) > a(i + 1) then swap a(i), a(i + 1): swap flag(i), flag(i + 1) next i, j rem================================================ k = 0 for i = 1 to 2*n s = s + flag(i) if s = 0 then k = k + 1 next if k = 1 then print "охранялась всегда" else print "не охранялась "; k - 1; " раз"
Решение задачи на Паскале:
const m=20; var a, flag: array [1..m] of integer; i,s,k,n,x: integer; begin writeln ('количество сторожей'); readln (n); j:=1; for i:=1 to n do begin writeln ('время прихода, ухода'); readln (a[j], a[j+1]); flag [j]:=1; flag [j+1]:=-1; j:=j+2; end; for j:=2*n downto 2 do for i:=1 to j-1 do if a[i]>a[i+1] then begin x:=a[i]; a[i]:=a[i+1]; a[i+1]:=x; x:=flag[i]; flag [i]:=flag [i+1]; flag [i+1]:=x; end; k:=0; s:=0; for i:=1 to 2*n do begin s:=s+flag [i]; if s=0 then k:=k+1; end; if k=1 then writeln ('галерея всегда охранялась') else writeln ('галерея оставалась без охраны',k-1,'раз'); end.
Тест:
Задача 3: N отрезков на координатной прямой заданы координатами своих концов. Определить количество связных областей.
Идея решения:
-
Заполняем массивы:
А: координатами начала и конца отрезков;
Flag:
- "1" - если соответствующий элемент массива А - координата начала отрезка;
- "-1" - если элемент массива А - координата конца отрезка;
- СОРТИРУЕМ массив А, одновременно переставляя элементы массива Flag.
-
Суммируем элементы массива Flag. Если текущая сумма обнулилась (но конец массива не достигнут), то, значит, получена одна связная область. Количество обнулений и будет количеством связных областей.
Решение на Бейсике:
input "введите количество отрезков", n dim a (2*n), flag (2*n) for i=1 to n*2 step 2 input "первая координата", a(i) flag (i)=1 input "вторая координата", a(i+1) flag (i+1)=-1 next for j=2*n to 2 step -1 for i= 1 to j-1 if a(i)>a(i+1) then swap a(i), a(i+1): swap flag(i), flag(i+1) next i, j for i=1 to 2*n s=s+flag (i) if s=0 then k=k+1 next print "количество связных областей ="; k
Решение задачи на Паскале:
const m=20; var a, flag: array [1..m] of integer; i,j,s,n,k,x: integer; begin writeln ('количество отрезков'); readln (n); j:=1; for i:=1 to n do begin writeln ('введите координаты начала и конца отрезка'); readln (a[j], a[j+1]); flag [j]:=1; flag [j+1]:=-1; j:=j+2; end; for j:=2*n downto 2 do for i:=1 to j-1 do if a[i]>a[i+1] then begin x:=a[i]; a[i]:=a[i+1]; a[i+1]:=x; x:=flag[i]; flag [i]:= flag [i+1]; flag [i+1]:=x; end; s:=0; k:=0; for i:=1 to 2*n do begin s:=s+flag [i]; if s=0 then k:=k+1; end; writeln ('количество связных областей=', k); end.
Тест:
Ключевые термины
- Связная область - область, соответствующая объединению отрезков.
Краткие итоги
При решении задач, в условиях которых озвучено наступление и окончание какого-то события (открытие-закрытие скобок, приход-уход сторожа, начало-конец отрезка) используется дополнительный массив "флажков". При наступлении события "флажок" принимает значение "1", при окончании - "-1".
При решении некоторых задач (например, на нахождение "связных" областей из отрезков на координатной прямой) потребуется использовать типовой алгоритм сортировки одномерного массива.
Набор для практики
Вопросы.
- Каким образом можно отметить элементы в наборе разнообразных данных, соответствующие разным событиям?
- При необходимости сортировки данных - каким образом учитывается событие, связанное с этим данным?
- Сколько связных областей дадут два отрезка, имеющие одну общую координату (начало одного совпадает с концом другого)?
- Какое количество случаев неохраняемости галереи выдаст программа, если время ухода одного из сторожей совпадает с временем прихода его сменщика?
Упражнения.
- В четырех различных кинотеатрах идут сеансы интересных фильмов. Некий зритель захотел побывать на всех четырех сеансах. Помогите установить - сможет ли зритель попасть на все 4 фильма, если известно время начала и конца каждого фильма, при этом временем "перехода" из кинотеатра в кинотеатр можно пренебречь.
- В строке символов находится программа на языке Паскаль (записанная в одну строку). Выяснить - нет ли ошибок в расстановке ключевых слов Begin и End в программе?