Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#12| Old Monk & Old Hero
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Различные авторы Весь текст 991.22 Kb

Программирование в теоремах и задачах

Предыдущая страница Следующая страница
1 2 3  4 5 6 7 8 9 10 11 12 13 14 ... 85

Замечание. В третьей альтернативе достаточно было бы увеличивать
одну из переменных k1, l1; вторая добавлена для симметрии.

     1.2.17.  Решить  предыдущую задачу, если известно лишь, что
x[1] <= ... <= x[k] и y[1] <= ... <= y[l] (возрастание  заменено
неубыванием).

     Решение.  Условие  возрастания  было использовано в третьей
альтернативе выбора: сдвинув k1 и l1 на 1, мы тем самым уменьша-
ли  на  1  количество  общих  элементов   в   x[k1+1]...x[k]   и
x[l1+1]...x[l]. Теперь это придется делать сложнее.

          ...
          end else begin {x[k1+1] = y[l1+1]}
          | t := x [k1+1];
          | while (k1 k) or (l1 <> l) do begin
  | if k1 = k then begin
  | | {l1 < l}
  | | l1 := l1 + 1;
  | | z[k1+l1] := y[l1];
  | end else if l1 = l then begin
  | | {k1 < k}
  | | k1 := k1 + 1;
  | | z[k1+l1] := x[k1];
  | end else if x[k1+1] <= y[l1+1] then begin
  | | k1 := k1 + 1;
  | | z[k1+l1] := x[k1];
  | end else if x[k1+1] >= y[l1+1] then begin
  | | l1 := l1 + 1;
  | | z[k1+l1] := y[l1];
  | end else begin
  | | { такого не бывает }
  | end;
  end;
  {k1 = k, l1 = l, массивы соединены}

Этот  процесс  можно  пояснить  так. Пусть у нас есть две стопки
карточек, отсортированных по алфавиту. Мы соединяем  их  в  одну
стопку,  выбирая каждый раз ту из верхних карточек обеих стопок,
которая идет раньше в алфавитном порядке.

     1.2.20. Даны два массива x[1] <= ... <= x[k] и y[1] <=  ...
<=  y[l].  Найти  их  "пересечение",  т.е. массив z[1] <= ... <=
z[m], содержащий их общие  элементы,  причем  кратность  каждого
элемента в массиве z равняется минимуму из его кратностей в мас-
сивах x и y. Число действий порядка k+l.

     1.2.21. Даны два массива x[1]<=...<=x[k] и  y[1]<=...<=y[l]
и  число q. Найти сумму вида x[i]+y[j], наиболее близкую к числу
q. (Число действий порядка k+l, дополнительная память - фиксиро-
ванное число целых переменных, сами массивы менять не разрешает-
ся.)
     Указание. Надо найти минимальное расстояние между элемента-
ми x[1]<=...<=x[k] и q-y[l]<=..<=q-y[1], что нетрудно сделать  в
ходе их слияния в один (воображаемый) массив.

     1.2.22. (из книги Д.Гриса) Некоторое  число  содержится  в
каждом из трех целочисленных неубывающих массивов x[1] <= ... <=
x[p],  y[1]  <=  ... <= y[q], z[1] <= ... <= z[r]. Найти одно из
таких чисел. Число действий должно быть порядка p + q + r.

     Решение.

  p1:=1; q1=1; r1:=1;
  {инвариант: x[p1]..x[p], y[q1]..y[q], z[r1]..z[r]
   содержат общий элемент }
  while not ((x[p1]=y[q1]) and (y[q1]=z[r1])) do begin
  | if x[p1]  первые
   элементы оставшихся частей равны}
  while not eq do begin
  | s := 1; k := 1;
  | {a[s][b[s]] - минимальное среди a[1][b[1]]..a[k][b[k]]}
  | while k <> n do begin
  | | k := k + 1;
  | | if a[k][b[k]] < a[s][b[s]] then begin
  | | | s := k;
  | | end;
  | end;
  | {a[s][b[s]] - минимальное среди a[1][b[1]]..a[n][b[n]]}
  | b [s] := b [s] + 1;
  | for k := 2 to n do begin
  | | eq := eq and (a[1][b[1]] = a[k][b[k]]);
  | end;
  end;
  writeln (a[1][b[1]]);

     1.2.25.  Приведенное  решение предыдущей задачи требует по-
рядка m*n*n действий. Придумать способ с числом действий порядка
m*n.
     Указание.  Придется  пожертвовать симметрией и выбрать одну
из строк за основную. Двигаясь по основной строке,  поддерживаем
такое  соотношение:  во  всех  остальных  строках отмечен макси-
мальный элемент, не  превосходящий  текущего  элемента  основной
строки.

     1.2.26. (Двоичный поиск) Дана  последовательность  x[1]  <=
...  <=  x[n] целых чисел и число a. Выяснить, содержится ли a в
этой последовательности, т. е. существует ли i из 1..n, для  ко-
торого x[i]=a. (Количество действий порядка log n.)

     Решение. (Предполагаем, что n > 0.)

  l := 1; r := n+1;
  {если a есть вообще, то есть и среди x[l]..x[r-1], r > l}
  while r - l <> 1 do begin
  | m := l + (r-l) div 2 ;
  | {l < m < r }
  | if x[m] <= a then begin
  | | l := m;
  | end else begin {x[m] > a}
  | | r := m;
  | end;
  end;
(Обратите внимание, что и в случае x[m] = a инвариант не наруша-
ется.)
     Каждый раз r-l уменьшается примерно вдвое, откуда и вытека-
ет требуемая оценка числа действий.
     Замечание.
l + (r-l) div 2 = (2l + (r-l)) div 2 = (r+l) div 2.

     1.2.27. (Из книги Д.Гриса) Дан массив x:  array  [1..n]  of
array  [1..m]  of  integer,  упорядоченный  по  "строкам"  и  по
"столбцам":
         x[i][j] <= x[i+1][j],
         x[i][j] <= x[i][j+1]
и число a. Требуется выяснить, встречается ли a среди x[i][j].

     Решение. Представляя себе  массив  a  как  матрицу  (прямо-
угольник,  заполненный числами), мы выберем прямоугольник, в ко-
тором только и может содержаться a, и будем его  сужать.  Прямо-
угольник этот будет содержать x[i][j] при 1<=i<=l и k<=j<=m.
                1                     k         m
               -----------------------------------
              1|                     |***********|
               |                     |***********|
               |                     |***********|
              l|                     |***********|
               |---------------------------------|
               |                                 |
              n|                                 |
               -----------------------------------
(допускаются пустые прямоугольники при l = 0 и k = m+1).

  l:=n; k:=1;
  {l>=0, k<=m+1, если a есть, то в описанном прямоугольнике}
  while (l > 0) and (k < m+1) and (x[l][k] <> a) do begin
  | if x[l][k] < a then begin
  | | k := k + 1; {левый столбец не содержит a, удаляем его}
  | end else begin {x[l][k] > a}
  | | l := l - 1; {нижняя строка не содержит a, удаляем ее}
  | end;
  end;
  {x[l][k] = a или прямоугольник пуст }
  answer:= (l > 0) and (k < m+1) ;

     Замечание.  Здесь та же ошибка: x[l][k] может оказаться не-
определенным. (Её исправление предоставляется читателю.)

     1.2.28. (Московская олимпиада по программированию) Дан не-
убывающий массив положительных целых чисел a[1] <= a[2]  <=...<=
a[n].  Найти наименьшее целое положительное число, не представи-
мое в виде суммы нескольких элементов этого массива (каждый эле-
мент массива может быть использован не более одного раза). Число
действий порядка n.

     Решение. Пусть известно, что  числа,  представимые  в  виде
суммы элементов a[1],...,a[k], заполняют отрезок от 1 до некото-
рого N. Если a[k+1] > N+1, то N+1 и будет минимальным числом, не
представимым  в виде суммы элементов массива a[1]..a[n]. Если же
a[k+1] <= N+1, то числа, представимые  в  виде  суммы  элементов
a[1]..a[k+1], заполняют отрезок от 1 до N+a[k+1].

  k := 0; N := 0;
  {инвариант: числа, представимые в виде суммы элементов массива
   a[1]..a[k], заполняют отрезок 1..N}
  while (k <> n) and (a[k+1] <= N+1) do begin
  | N := N + a[k+1];
  | k := k + 1;
  end;
  {(k = n) или (a[k+1] > N+1); в обоих случаях ответ N+1}
  writeln (N+1);

(Снова тот же дефект: в условии цикла при ложном первом  условии
второе не определено.)

     1.2.29.  (Для  знакомых с основами алгебры) В целочисленном
массиве a[1]..a[n] хранится перестановка чисел 1..n  (каждое  из
чисел встречается по одному разу).
     (а) Определить четность перестановки. (И в (а), и в (б) ко-
личество действий порядка n.)
     (б)  Не используя других массивов, заменить перестановку на
обратную (если до работы программы a[i]=j, то после должно  быть
a[j]=i).

     Указание.  (а)  Четность  перестановки  определяется  коли-
чеством циклов. Чтобы отличать уже пройденные циклы, у  их  эле-
ментов можно, например, менять знак. (б) Обращение производим по
циклам.

     1.2.30. Дан массив a[1..n] и число b. Переставить  числа  в
массиве  таким  образом, чтобы слева от некоторой границы стояли
числа, меньшие или равные b, а справа от границы -  большие  или
равные b.

     Решение.

        l:=0; r:=n;
        {инвариант: a[1]..a[l]<=b; a[r+1]..a[n]>=b}
        while l <> r do begin
        | if a[l+1] <= b then begin
        | | l:=l+1;
        | end else if a[r] >=b then begin
        | | r:=r-1;
        | end else begin {a[l+1]>b; a[r]
Предыдущая страница Следующая страница
1 2 3  4 5 6 7 8 9 10 11 12 13 14 ... 85
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама