В этом разделе рассматриваются различные варианты одной
задач. Пусть имеется n городов, пронумерованных числами
от 1 до n. Для каждой пары городов
с номерами i, j в таблице a[i][j] хранится
i
в город j. Считается, что рейсы существуют между любыми
городами, $${a[i][i]}={0}$$ при всех i, a[i][j]
может отличаться от a[j][i]. Наименьшей i в j считается минимально возможная
сумма цен билетов для маршрутов (в том числе
с пересадками), ведущих из i в j. (Она не
превосходит a[i][j], но может быть меньше.)
В предлагаемых ниже задачах требуется найти наименьшую
a и на время работы
алгоритма.
9.1.1.
Предположим, что не существует
Решение. Маршрут длиной больше n всегда содержит цикл,
поэтому n, а их конечное число.
Во всех следующих задачах предполагается, что это условие (отсутствие циклов с отрицательной суммой) выполнено.
9.1.2.
Найти наименьшую
Решение. Обозначим через МинСт(1,s,k) наименьшую
1 в s менее чем
с k пересадками. Тогда выполняется такое соотношение:$${МинСт}({1},{s},{k+1}) =
min \Bigl({МинСт(1,s,k)},
\min_{i=1..n} {МинСт(1,i,k)}+{a[i]}\!{[s]})\Bigr)$$
Как отмечалось выше, искомым ответом является МинСт(1,i,n) для всех $${i}={1}\ldots{n}$$.
k:= 1;
for i := 1 to n do begin x[i] := a[1][i]; end;
{инвариант: x[i] = МинСт(1,i,k)}
while k <> n do begin
| for s := 1 to n do begin
| | y[s] := x[s];
| | for i := 1 to n do begin
| | | if y[s] > x[i]+a[i][s] then begin
| | | | y[s] := x[i]+a[i][s];
| | | end;
| | end
| | {y[s] = МинСт(1,s,k+1)}
| end;
| for i := 1 to n do begin x[s] := y[s]; end;
| k := k + 1;
end;
Приведенный алгоритм называют алгоритмом динамического программирования, или алгоритмом Форда-Беллмана.
9.1.3.
Доказать, что программа останется правильной, если не
заводить массива y, а производить изменения в самом
массиве x (заменив в программе все вхождения
буквы y на x и затем удалить ставшие лишними
строки).
Решение.
Этот алгоритм может быть i, j (а не только при $${i}={1}$$ ), а можно
сократить время работы до $$O({n}^2)$$. Правда, в последнем
случае нам потребуется, чтобы все цены a[i][j] были
неотрицательны.
9.1.4.
Найти наименьшую i, j за время $$O({n}^3)$$.
Решение. Для $${k} = {0}\ldots{n}$$ через A(i,j,k)
обозначим наименьшую i в j,
если в качестве пересадочных разрешено использовать только
пункты с номерами не больше k. Тогда
A(i,j,0) = a[i][j],
A(i,j,k+1)=min(A(i,j,k), A(i,k+1,k)+{A(k+1,j,k))
(два варианта соответствуют неиспользованию и использованию
пункта k+1 в качестве пересадочного; отметим, что в нем
незачем бывать более одного раза).
Этот алгоритм называют алгоритмом Флойда.
9.1.5.
Как проверить за $$O(n)$$ действий, имеет ли n
вершинами
циклы с отрицательной суммой?
Указание.
Можно применять
9.1.6. Имеется $$n$$ валют и таблица обменных курсов (сколько флоринов дают за талер и т.п.). Коммерсант хочет неограниченно обогатиться, обменивая свой начальный капитал туда-сюда по этим курсам. Как проверить, возможно ли это?
Указание.
После логарифмирования деньги уподобляются
9.1.7.
Известно, что все цены неотрицательны. Найти наименьшую
Решение. В процессе работы алгоритма некоторые города
будут выделенными (в начале - только город 1,
в конце - все). При этом:
i хранится
наименьшая i хранится
наименьшая Множество выделенных городов расширяется на основании
следующего замечания: если среди всех невыделенных городов
взять тот, для которого хранимое число минимально, то это
число является истинной наименьшей
Добавив выбранный город к выделенным, мы должны
скорректировать информацию, хранимую для невыделенных
городов. При этом достаточно учесть лишь пути, в которых
новый город является последним пунктом пересадки, а это
легко сделать, так как минимальную
При самом бесхитростном способе хранения множества
выделенных городов (в булевском
Этот алгоритм называют
9.1.8. Имеется $$n$$ городов, соединенных дорогами (с односторонним движением). Для любых городов $$i,j$$ известен максимальный вес груза, который можно везти из $$i$$ в $$j$$ (грузоподъемность дороги). Найти за время $$O(n^2)$$ для всех городов максимальный вес груза, который в них можно привезти из столицы.
Указание.
Действовать аналогично
Отыскание кратчайшего пути имеет естественную i в город j?
9.1.9.
Доказать, что эта
9.1.10.
Доказать, что таким образом определенное
9.1.11.
Доказать, что задача о
9.1.12.
Начиная с какого элемента можно гарантировать
Обычное (не модифицированное) a[i][j] равно 1, если рейс есть, и 0, если
рейса нет. Возведем матрицу a (обычным образом)
в степень k и посмотрим на ее ( i - j )-ый
элемент.
9.1.13. Чему он равен?
Ответ. Числу различных способов попасть из i в j
за k рейсов (с k-1 пересадками).
При описании кратчайших путей случай, когда есть не все
рейсы, можно свести к исходному, введя фиктивные рейсы
с бесконечно большой (или достаточно большой)
9.1.14.
Доказать, что
Указание.
Что надо сделать на каждом шаге? Выбрать невыделенный город
с минимальной
Наиболее простой случай задачи о
Для этого случая задачи о
Поиск в ширину.
Надо перечислить все вершины
9.2.1. Придумать алгоритм решения этой задачи с числом действий не более $$C\cdot{}$$ (число ребер, выходящих из интересующих нас вершин).
Решение. Эта задача рассматривалась в лекции 6, задача 6.3.9. Здесь мы приведем подробное решение.
Пусть num[i] - количество ребер, выходящих из i, $${out[i][1]},\ldots,{out[i][num[i]]}$$ - вершины, куда
ведут
procedure Доступные (i: integer);
| {напечатать все вершины, доступные из i, включая i}
| var X: подмножество 1..n;
| P: подмножество 1..n;
| q, v, w: 1..n;
| k: integer;
begin
| ...сделать X, P пустыми;
| writeln (i);
| ...добавить i к X, P;
| {(1) P = множество напечатанных вершин; P содержит i;
| (2) напечатаны только доступные из i вершины;
| (3) X - подмножество P;
| (4) все напечатанные вершины, из которых выходит
| ребро в ненапечатанную вершину, принадлежат X}
| while X непусто do begin
| | ...взять какой-нибудь элемент X в v;
| | for k := 1 to num [v] do begin
| | | w := out [v][k];
| | | if w не принадлежит P then begin
| | | | writeln (w);
| | | | добавить w в P;
| | | | добавить w в X;
| | | end;
| | end;
| end;
end;
Тогда нам было безразлично, какой именно элемент
множества X выбирается. Если мы будем считать X
очередью (первым пришел - первым ушел), то эта программа
напечатает все вершины, доступные из i, в порядке
возрастания их расстояния от i (числа ребер на
i ). Докажем это.
Обозначим через $$V(k)$$ множество всех вершин, i (в описанном смысле) равно $$k$$. Имеет
место такое соотношение:$$V(k+1) = \text{(концы ребер с началами в V(k))}
\setminus (V(0)
\cup \ldots
\cup V(k))$$
Докажем, что для любого $$k=0,1,2\ldots$$ в ходе работы
программы будет такой момент (после очередной while ), когда$$\begin{quote}
в очереди стоят все элементы V(k) и только они; \\
напечатаны все элементы V(0),\ldots,V(k).
\end{quote}$$
(Для $$k=0$$ - это состояние перед циклом.) Рассуждая по
Поиск в глубину.
Рассматривая
Имеется естественное отображение
Будем предполагать, что для каждой вершины
Другими словами, на путях, выходящих из
9.2.2.
Написать программу
Указание.
Возьмем программу
Замечание.Напомним, что в лекции 8 упоминались две возможности устранения
9.2.3.
Указание. (а) Каждую связную компоненту можно раскрашивать отдельно. (б) Выбрав цвет одной вершины и обходя ее связную компоненту, мы определяем единственно возможный цвет остальных.
Замечание.В этой задаче безразлично, производить
9.2.4.
Составить нерекурсивный алгоритм
Решение. Предположим, что i известно число num[i] выходящих из нее ребер и номера вершин $${dest[i][1]},\ldots,{dest[i][num[i]]}$$, в которые эти
Для начала добавим к графу вершину 0, из которой
Алгоритм хранит путь, выходящий из нулевой вершины и идущий
по ребрам l отводится для длины этого
пути. Путь образован вершинами $${vert[1]}\ldots{vert[l]}$$ и ребрами, имеющими номера $${edge[1]}\ldots{edge[l]}$$. Номер относится
к vert[s]. Тем
самым для всех s должны выполняться dest[vert[l]][, не включается в vert. Кроме того, для последнего равняться num[vert[l]]+1.
В процессе работы алгоритм будет печатать номера вершин,
при этом соблюдая требование "вершина напечатана только
после тех вершин, в которые из нее ведут
(vert[1]...vert[l]) не напечатаны, но
свернув с пути налево, мы немедленно упираемся
в напечатанную вершину.Вот что получается:
l:=1; vert[1]:=0; edge[1]:=1;
while not( (l=1) and (edge[1]=n+1)) do begin
| if edge[l]=num[vert[l]]+1 then begin
| | {путь кончается в пустоте, поэтому все вершины,
| | следующие за vert[l], напечатаны - можно
| | печатать vert[l]}
| | writeln (vert[l]);
| | l:=l-1; edge[l]:=edge[l]+1;
| end else begin
| | {edge[l] <= num[vert[l]], путь кончается в
| | вершине}
| | lastvert:= dest[vert[l]][edge[l]]; {последняя}
| | if lastvert напечатана then begin
| | | edge[l]:=edge[l]+1;
| | end else begin
| | | l:=l+1; vert[l]:=lastvert; edge[l]:=1;
| | end;
| end;
end;
{путь сразу же ведет в пустоту, поэтому все вершины
левее, то есть 1..n, напечатаны}
9.2.5.
Доказать, что если в
Решение. Пусть это не так. Каждая вершина может печататься
только один раз, так что с некоторого момента вершины не
печатаются. В - но и это не беспредельно.
Тем самым мы построили искомый нерекурсивный алгоритм
9.2.6. Доказать, что время работы этого алгоритма не превосходит $$O(\text{число вершин}+\text{число ребер})$$.
9.2.7. Как модифицировать алгоритм так, чтобы он отыскивал один из циклов, если таковые имеются, и производил топологическую сортировку, если циклов нет?
В этом разделе рассматриваются различные варианты одной
задач. Пусть имеется n городов, пронумерованных числами
от 1 до n. Для каждой пары городов
с номерами i, j в таблице a[i][j] хранится
i
в город j. Считается, что рейсы существуют между любыми
городами, $${a[i][i]}={0}$$ при всех i, a[i][j]
может отличаться от a[j][i]. Наименьшей i в j считается минимально возможная
сумма цен билетов для маршрутов (в том числе
с пересадками), ведущих из i в j. (Она не
превосходит a[i][j], но может быть меньше.)
В предлагаемых ниже задачах требуется найти наименьшую
a и на время работы
алгоритма.
9.1.1.
Предположим, что не существует
Решение. Маршрут длиной больше n всегда содержит цикл,
поэтому n, а их конечное число.
Во всех следующих задачах предполагается, что это условие (отсутствие циклов с отрицательной суммой) выполнено.
9.1.2.
Найти наименьшую
Решение. Обозначим через МинСт(1,s,k) наименьшую
1 в s менее чем
с k пересадками. Тогда выполняется такое соотношение:$${МинСт}({1},{s},{k+1}) =
min \Bigl({МинСт(1,s,k)},
\min_{i=1..n} {МинСт(1,i,k)}+{a[i]}\!{[s]})\Bigr)$$
Как отмечалось выше, искомым ответом является МинСт(1,i,n) для всех $${i}={1}\ldots{n}$$.
k:= 1;
for i := 1 to n do begin x[i] := a[1][i]; end;
{инвариант: x[i] = МинСт(1,i,k)}
while k <> n do begin
| for s := 1 to n do begin
| | y[s] := x[s];
| | for i := 1 to n do begin
| | | if y[s] > x[i]+a[i][s] then begin
| | | | y[s] := x[i]+a[i][s];
| | | end;
| | end
| | {y[s] = МинСт(1,s,k+1)}
| end;
| for i := 1 to n do begin x[s] := y[s]; end;
| k := k + 1;
end;
Приведенный алгоритм называют алгоритмом динамического программирования, или алгоритмом Форда-Беллмана.
9.1.3.
Доказать, что программа останется правильной, если не
заводить массива y, а производить изменения в самом
массиве x (заменив в программе все вхождения
буквы y на x и затем удалить ставшие лишними
строки).
Решение.
Этот алгоритм может быть i, j (а не только при $${i}={1}$$ ), а можно
сократить время работы до $$O({n}^2)$$. Правда, в последнем
случае нам потребуется, чтобы все цены a[i][j] были
неотрицательны.
9.1.4.
Найти наименьшую i, j за время $$O({n}^3)$$.
Решение. Для $${k} = {0}\ldots{n}$$ через A(i,j,k)
обозначим наименьшую i в j,
если в качестве пересадочных разрешено использовать только
пункты с номерами не больше k. Тогда
A(i,j,0) = a[i][j],
A(i,j,k+1)=min(A(i,j,k), A(i,k+1,k)+{A(k+1,j,k))
(два варианта соответствуют неиспользованию и использованию
пункта k+1 в качестве пересадочного; отметим, что в нем
незачем бывать более одного раза).
Этот алгоритм называют алгоритмом Флойда.
9.1.5.
Как проверить за $$O(n)$$ действий, имеет ли n
вершинами
циклы с отрицательной суммой?
Указание.
Можно применять
9.1.6. Имеется $$n$$ валют и таблица обменных курсов (сколько флоринов дают за талер и т.п.). Коммерсант хочет неограниченно обогатиться, обменивая свой начальный капитал туда-сюда по этим курсам. Как проверить, возможно ли это?
Указание.
После логарифмирования деньги уподобляются
9.1.7.
Известно, что все цены неотрицательны. Найти наименьшую
Решение. В процессе работы алгоритма некоторые города
будут выделенными (в начале - только город 1,
в конце - все). При этом:
i хранится
наименьшая i хранится
наименьшая Множество выделенных городов расширяется на основании
следующего замечания: если среди всех невыделенных городов
взять тот, для которого хранимое число минимально, то это
число является истинной наименьшей
Добавив выбранный город к выделенным, мы должны
скорректировать информацию, хранимую для невыделенных
городов. При этом достаточно учесть лишь пути, в которых
новый город является последним пунктом пересадки, а это
легко сделать, так как минимальную
При самом бесхитростном способе хранения множества
выделенных городов (в булевском
Этот алгоритм называют
9.1.8. Имеется $$n$$ городов, соединенных дорогами (с односторонним движением). Для любых городов $$i,j$$ известен максимальный вес груза, который можно везти из $$i$$ в $$j$$ (грузоподъемность дороги). Найти за время $$O(n^2)$$ для всех городов максимальный вес груза, который в них можно привезти из столицы.
Указание.
Действовать аналогично
Отыскание кратчайшего пути имеет естественную i в город j?
9.1.9.
Доказать, что эта
9.1.10.
Доказать, что таким образом определенное
9.1.11.
Доказать, что задача о
9.1.12.
Начиная с какого элемента можно гарантировать
Обычное (не модифицированное) a[i][j] равно 1, если рейс есть, и 0, если
рейса нет. Возведем матрицу a (обычным образом)
в степень k и посмотрим на ее ( i - j )-ый
элемент.
9.1.13. Чему он равен?
Ответ. Числу различных способов попасть из i в j
за k рейсов (с k-1 пересадками).
При описании кратчайших путей случай, когда есть не все
рейсы, можно свести к исходному, введя фиктивные рейсы
с бесконечно большой (или достаточно большой)
9.1.14.
Доказать, что
Указание.
Что надо сделать на каждом шаге? Выбрать невыделенный город
с минимальной
Наиболее простой случай задачи о
Для этого случая задачи о
Поиск в ширину.
Надо перечислить все вершины
9.2.1. Придумать алгоритм решения этой задачи с числом действий не более $$C\cdot{}$$ (число ребер, выходящих из интересующих нас вершин).
Решение. Эта задача рассматривалась в лекции 6, задача 6.3.9. Здесь мы приведем подробное решение.
Пусть num[i] - количество ребер, выходящих из i, $${out[i][1]},\ldots,{out[i][num[i]]}$$ - вершины, куда
ведут
procedure Доступные (i: integer);
| {напечатать все вершины, доступные из i, включая i}
| var X: подмножество 1..n;
| P: подмножество 1..n;
| q, v, w: 1..n;
| k: integer;
begin
| ...сделать X, P пустыми;
| writeln (i);
| ...добавить i к X, P;
| {(1) P = множество напечатанных вершин; P содержит i;
| (2) напечатаны только доступные из i вершины;
| (3) X - подмножество P;
| (4) все напечатанные вершины, из которых выходит
| ребро в ненапечатанную вершину, принадлежат X}
| while X непусто do begin
| | ...взять какой-нибудь элемент X в v;
| | for k := 1 to num [v] do begin
| | | w := out [v][k];
| | | if w не принадлежит P then begin
| | | | writeln (w);
| | | | добавить w в P;
| | | | добавить w в X;
| | | end;
| | end;
| end;
end;
Тогда нам было безразлично, какой именно элемент
множества X выбирается. Если мы будем считать X
очередью (первым пришел - первым ушел), то эта программа
напечатает все вершины, доступные из i, в порядке
возрастания их расстояния от i (числа ребер на
i ). Докажем это.
Обозначим через $$V(k)$$ множество всех вершин, i (в описанном смысле) равно $$k$$. Имеет
место такое соотношение:$$V(k+1) = \text{(концы ребер с началами в V(k))}
\setminus (V(0)
\cup \ldots
\cup V(k))$$
Докажем, что для любого $$k=0,1,2\ldots$$ в ходе работы
программы будет такой момент (после очередной while ), когда$$\begin{quote}
в очереди стоят все элементы V(k) и только они; \\
напечатаны все элементы V(0),\ldots,V(k).
\end{quote}$$
(Для $$k=0$$ - это состояние перед циклом.) Рассуждая по
Поиск в глубину.
Рассматривая
Имеется естественное отображение
Будем предполагать, что для каждой вершины
Другими словами, на путях, выходящих из
9.2.2.
Написать программу
Указание.
Возьмем программу
Замечание.Напомним, что в лекции 8 упоминались две возможности устранения
9.2.3.
Указание. (а) Каждую связную компоненту можно раскрашивать отдельно. (б) Выбрав цвет одной вершины и обходя ее связную компоненту, мы определяем единственно возможный цвет остальных.
Замечание.В этой задаче безразлично, производить
9.2.4.
Составить нерекурсивный алгоритм
Решение. Предположим, что i известно число num[i] выходящих из нее ребер и номера вершин $${dest[i][1]},\ldots,{dest[i][num[i]]}$$, в которые эти
Для начала добавим к графу вершину 0, из которой
Алгоритм хранит путь, выходящий из нулевой вершины и идущий
по ребрам l отводится для длины этого
пути. Путь образован вершинами $${vert[1]}\ldots{vert[l]}$$ и ребрами, имеющими номера $${edge[1]}\ldots{edge[l]}$$. Номер относится
к vert[s]. Тем
самым для всех s должны выполняться dest[vert[l]][, не включается в vert. Кроме того, для последнего равняться num[vert[l]]+1.
В процессе работы алгоритм будет печатать номера вершин,
при этом соблюдая требование "вершина напечатана только
после тех вершин, в которые из нее ведут
(vert[1]...vert[l]) не напечатаны, но
свернув с пути налево, мы немедленно упираемся
в напечатанную вершину.Вот что получается:
l:=1; vert[1]:=0; edge[1]:=1;
while not( (l=1) and (edge[1]=n+1)) do begin
| if edge[l]=num[vert[l]]+1 then begin
| | {путь кончается в пустоте, поэтому все вершины,
| | следующие за vert[l], напечатаны - можно
| | печатать vert[l]}
| | writeln (vert[l]);
| | l:=l-1; edge[l]:=edge[l]+1;
| end else begin
| | {edge[l] <= num[vert[l]], путь кончается в
| | вершине}
| | lastvert:= dest[vert[l]][edge[l]]; {последняя}
| | if lastvert напечатана then begin
| | | edge[l]:=edge[l]+1;
| | end else begin
| | | l:=l+1; vert[l]:=lastvert; edge[l]:=1;
| | end;
| end;
end;
{путь сразу же ведет в пустоту, поэтому все вершины
левее, то есть 1..n, напечатаны}
9.2.5.
Доказать, что если в
Решение. Пусть это не так. Каждая вершина может печататься
только один раз, так что с некоторого момента вершины не
печатаются. В - но и это не беспредельно.
Тем самым мы построили искомый нерекурсивный алгоритм
9.2.6. Доказать, что время работы этого алгоритма не превосходит $$O(\text{число вершин}+\text{число ребер})$$.
9.2.7. Как модифицировать алгоритм так, чтобы он отыскивал один из циклов, если таковые имеются, и производил топологическую сортировку, если циклов нет?
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.