Опубликован: 21.03.2012 | Доступ: свободный | Студентов: 2973 / 231 | Оценка: 4.44 / 4.19 | Длительность: 06:43:00
Специальности: Программист
Лекция 8:

Задачи, сгруппированные по методам решения. Использование дополнительного массива "флажков" (три задачи - один алгоритм)

< Лекция 7 || Лекция 8 || Лекция 9 >
Аннотация: Продолжаем отрабатывать пройденный прием (использование дополнительного массива "флажков") в ситуациях, когда необходимо отметить наступление и окончание какого-то события (открытие-закрытие скобок, приход-уход сторожа, начало-конец отрезка). При наступлении события "флажок" примет значение "1", при окончании - "-1". Материалы лекции базируются на типовых алгоритмах обработки одномерных массивов и строк. Цель лекции: научиться применять изученный метод при решении классических задач.
Ключевые слова: выражение, прямой

Рассмотрим несколько практических задач.

Задача 1: В строке, содержащей арифметическое выражение проверить, правильно ли расставлены скобки. В случае лишних скобок - не считать неправильным расстановку скобок (например: ((а+в)) -скобки расставлены верно).

Идея решения:

  1. Допустим, дано арифметическое выражение: (а + в ((4а - 8) в + 3) - 15в)
  2. Резервируем два массива: А$ и Flag. "Разбираем" строку, в которой хранится арифметическое выражение (применив типовой алгоритм "РАЗБОРА" СТРОКИ НА СИМВОЛЫ), помещая каждый символ в элемент массива А$.

    Массив Flag заполняем флажками:

    • "1" - если элемент массива А$ - открывающаяся скобка;
    • "-1" - если элемент массива А$ - закрывающаяся скобка (рис. 7.1).

      Рис. 7.1.
  3. Суммируем элементы массива 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.
    

    Тест:

    Дано: (4*5+1)*((2/6-2*3)+4)) (6+56))-90*(5-2*(3-7/3)
    Результат: скобки расставлены верно скобки расставлены неверно

Задача 2: В картинной галерее работают сторожа. Для каждого сторожа известно время прихода на работу и время ухода. Определить, всегда ли галерея охраняется.

Идея решения:Пример (табл. 7.1):

Таблица 7.1.
Время прихода Время ухода
1 сторож 8.00 12.00
2 сторож 11.00 16.00
3 сторож 15.00 19.30
4 сторож 20.00 23.50
  1. Заполняем массивы:

    А: временем прихода и ухода сторожей;

    Flag:

    • "1" - если соответствующий элемент массива А - время прихода сторожа;
    • "-1" - если элемент массива А - время ухода сторожа;

    Рис. 7.2.
  2. СОРТИРУЕМ массив А, одновременно переставляя элементы массива flag:


    Рис. 7.3.
  3. Суммируем элементы второго массива. Если текущая сумма обнулилась (но конец массива не достигнут), то, значит, галерея осталась без охраны (в 19.30 сторож ушел, а смена еще не пришла).


    Рис. 7.4.

    Решение на Бейсике:

    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.

    Тест:

    Дано:
    n=3
    8
    10
    9
    12
    11
    13
    n=3
    8
    10
    9
    12
    13
    14
    Результат: охранялась не охранялась 1 раз

Задача 3: N отрезков на координатной прямой заданы координатами своих концов. Определить количество связных областей.

Идея решения:

  1. Заполняем массивы:

    А: координатами начала и конца отрезков;

    Flag:

    • "1" - если соответствующий элемент массива А - координата начала отрезка;
    • "-1" - если элемент массива А - координата конца отрезка;
  2. СОРТИРУЕМ массив А, одновременно переставляя элементы массива Flag.
  3. Суммируем элементы массива 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.
    

Тест:

Дано:
n=3
1
5
4
9
11
15
n=3
1
3
4
9
11
15
Результат: 2 3

Ключевые термины

  • Связная область - область, соответствующая объединению отрезков.

Краткие итоги

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

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

Набор для практики

Вопросы.

  • Каким образом можно отметить элементы в наборе разнообразных данных, соответствующие разным событиям?
  • При необходимости сортировки данных - каким образом учитывается событие, связанное с этим данным?
  • Сколько связных областей дадут два отрезка, имеющие одну общую координату (начало одного совпадает с концом другого)?
  • Какое количество случаев неохраняемости галереи выдаст программа, если время ухода одного из сторожей совпадает с временем прихода его сменщика?

Упражнения.

  • В четырех различных кинотеатрах идут сеансы интересных фильмов. Некий зритель захотел побывать на всех четырех сеансах. Помогите установить - сможет ли зритель попасть на все 4 фильма, если известно время начала и конца каждого фильма, при этом временем "перехода" из кинотеатра в кинотеатр можно пренебречь.
  • В строке символов находится программа на языке Паскаль (записанная в одну строку). Выяснить - нет ли ошибок в расстановке ключевых слов Begin и End в программе?
< Лекция 7 || Лекция 8 || Лекция 9 >