<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.26.129.35&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.26.129.35&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/94.26.129.35"/>
		<updated>2026-05-19T18:03:58Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BF%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%BC&amp;diff=39609</id>
		<title>Сортировка пузырьком</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BF%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%BC&amp;diff=39609"/>
				<updated>2014-06-16T21:34:16Z</updated>
		
		<summary type="html">&lt;p&gt;94.26.129.35: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка простыми обменами''', '''сортировка пузырьком''' (англ. ''bubble sort'') — один из квадратичных алгоритмов сортировки.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм ==&lt;br /&gt;
Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами. За каждый проход по массиву как минимум один элемент встает на свое место, поэтому необходимо совершить не более &amp;lt;tex&amp;gt; n - 1 &amp;lt;/tex&amp;gt; проходов, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; размер массива, чтобы отсортировать массив.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
Ниже приведен псевдокод сортировки пузырьком, на вход которой подается массив &amp;lt;tex&amp;gt; a[0..n - 1] &amp;lt;/tex&amp;gt;.&lt;br /&gt;
 '''function''' bubbleSort(a):&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 2&lt;br /&gt;
      '''for''' j = 0 '''to''' n - 2&lt;br /&gt;
        '''if''' a[j] &amp;gt; a[j + 1]&lt;br /&gt;
          swap(a[j], a[j + 1])&lt;br /&gt;
&lt;br /&gt;
== Оптимизация ==&lt;br /&gt;
* Можно заметить, что после &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;-ой итерации внешнего цикла &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; последних элементов уже находятся на своих местах в отсортированном порядке, поэтому нет необходимости производить их сравнения друг с другом. Следовательно, внутренний цикл можно выполнять не до &amp;lt;tex&amp;gt; n - 2 &amp;lt;/tex&amp;gt;, а до &amp;lt;tex&amp;gt; n - i - 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Также заметим, что если после выполнения внутреннего цикла не произошло ни одного обмена, то массив уже отсортирован, и продолжать что-то делать бессмысленно. Поэтому внутренний цикл можно выполнять не &amp;lt;tex&amp;gt; n - 1 &amp;lt;/tex&amp;gt; раз, а до тех пор, пока во внутреннем цикле происходят обмены.&lt;br /&gt;
&lt;br /&gt;
При использовании первой оптимизации сортировка принимает следующий вид:&lt;br /&gt;
 '''function''' bubbleSort(a):&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 2&lt;br /&gt;
       '''for''' j = 0 '''to''' n - i - 2&lt;br /&gt;
          '''if''' a[j] &amp;gt; a[j + 1]&lt;br /&gt;
             swap(a[j], a[j + 1])&lt;br /&gt;
&lt;br /&gt;
При использовании же обеих оптимизаций сортировка пузырьком выглядит так:&lt;br /&gt;
 '''function''' bubbleSort(a):&lt;br /&gt;
    i = 0&lt;br /&gt;
    t = ''true''&lt;br /&gt;
    '''while''' t&lt;br /&gt;
      t = ''false''&lt;br /&gt;
      '''for''' j = 0 '''to''' n - i - 2&lt;br /&gt;
        '''if''' a[j] &amp;gt; a[j + 1]&lt;br /&gt;
          swap(a[j], a[j + 1])&lt;br /&gt;
          t = ''true''&lt;br /&gt;
      i = i + 1&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
В данной сортировке выполняются всего два различных вида операции: сравнение элементов и их обмен. Поэтому время всего алгоритма &amp;lt;tex&amp;gt; T = T_1 + T_2 &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; T_1 &amp;lt;/tex&amp;gt; {{---}} время, затрачиваемое на сравнение элементов, а &amp;lt;tex&amp;gt; T_2 &amp;lt;/tex&amp;gt; {{---}} время, за которое мы производим все необходимые обмены элементов.&lt;br /&gt;
&lt;br /&gt;
Так как в алгоритме меняться местами могут только соседние элементы, то каждый обмен уменьшает количество [[Таблица инверсий|инверсий]] на единицу. Следовательно, количество обменов равно количеству инверсий в исходном массиве вне зависимости от реализации сортировки. Максимальное количество инверсий содержится в массиве, элементы которого отсортированы по убыванию. Несложно посчитать, что количество инверсий в таком массиве &amp;lt;tex&amp;gt; \frac {n (n - 1)} {2} &amp;lt;/tex&amp;gt;. Получаем, что &amp;lt;tex&amp;gt; T_2 = O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В неоптимизированной реализации на каждой итерации внутреннего цикла производятся &amp;lt;tex&amp;gt; n - 1 &amp;lt;/tex&amp;gt; сравнений, а так как внутренний цикл запускается также &amp;lt;tex&amp;gt; n - 1 &amp;lt;/tex&amp;gt; раз, то за весь алгоритм сортировки производятся &amp;lt;tex&amp;gt; (n - 1)^2 &amp;lt;/tex&amp;gt; сравнений.&lt;br /&gt;
&lt;br /&gt;
В оптимизированной версии точное количество сравнений зависит от исходного массива. Известно, что худший случай равен &amp;lt;tex&amp;gt; \frac {n (n - 1)} {2} &amp;lt;/tex&amp;gt;, а лучший {{---}} &amp;lt;tex&amp;gt; n-1 &amp;lt;/tex&amp;gt;. Следовательно, &amp;lt;tex&amp;gt; T_1 = O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;tex&amp;gt; T = T_1 + T_2 = O(n^2) + O(n^2) = O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример работы алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Возьмём массив &amp;lt;tex&amp;gt; [5, 1, 4, 2, 8] &amp;lt;/tex&amp;gt; и отсортируем значения по возрастанию, используя сортировку пузырьком. Выделены те элементы, которые сравниваются на данном этапе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Первый проход:'''&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| До&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| После&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Описание шага&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| '''5 1''' 4 2 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| '''1 5''' 4 2 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| Здесь алгоритм сравнивает два первых элемента и меняет их местами.&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 '''5 4''' 2 8 &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 '''4 5''' 2 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| Меняет местами, так как 5 &amp;gt; 4&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 4 '''5 2''' 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 4 '''2 5''' 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| Меняет местами, так как 5 &amp;gt; 2&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 4 2 '''5 8''' &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 4 2 '''5 8'''&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| Теперь, ввиду того, что элементы стоят на своих местах (8 &amp;gt; 5), алгоритм не меняет их местами.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Второй проход:'''&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| До&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| После&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Описание шага&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| '''1 4''' 2 5 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| '''1 4''' 2 5 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 '''4 2''' 5 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 '''2 4''' 5 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| Меняет местами, так как 4 &amp;gt; 2&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 2 '''4 5''' 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 2 '''4 5''' 8&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;|&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 2 4 '''5 8''' &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| 1 2 4 '''5 8'''&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь массив полностью отсортирован, но неоптимизированный алгоритм проведет еще два прохода, на которых ничего не изменится, в отличии от алгоритма, использующего вторую оптимизацию, который сделает один проход и прекратит свою работу, так как не сделает за этот проход ни одного обмена.&lt;br /&gt;
&lt;br /&gt;
== Модификации ==&lt;br /&gt;
&lt;br /&gt;
=== Сортировка чет-нечет ===&lt;br /&gt;
'''Сортировка чет-нечет''' (англ. ''odd-even sort'')  {{---}} модификация пузырьковой сортировки, основанная на сравнении элементов стоящих на четных и нечетных позициях независимо друг от друга. Сложность {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Псевдокод указан ниже:&lt;br /&gt;
 '''function''' oddEvenSort(a):&lt;br /&gt;
   '''for''' i = 0 '''to''' n - 1 &lt;br /&gt;
       '''if''' i '''mod''' 2 = 0&lt;br /&gt;
            '''for''' j = 2 '''to''' n - 1 '''step''' 2&lt;br /&gt;
                '''if''' a[j] &amp;lt; a[j - 1]&lt;br /&gt;
                    swap(a[j - 1], a[j])  &lt;br /&gt;
       '''else'''      &lt;br /&gt;
            '''for''' j = 1 '''to''' n - 1 '''step''' 2&lt;br /&gt;
                '''if''' a[j] &amp;lt; a[j - 1]&lt;br /&gt;
                    swap(a[j - 1], a[j])&lt;br /&gt;
&lt;br /&gt;
Преимущество этой сортировки {{---}} на нескольких процессорах она выполняется быстрее, так как четные и нечетные индексы сортируются параллельно.&lt;br /&gt;
&lt;br /&gt;
=== Сортировка расческой ===&lt;br /&gt;
'''Сортировка расческой''' (англ. ''comb sort'')  {{---}} модификация пузырьковой сортировки, основанной на сравнении элементов на расстоянии.  Сложность  {{---}}&amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;, но стремится к &amp;lt;tex&amp;gt;         O(n \log n) &amp;lt;/tex&amp;gt;.  Является самой быстрой квадратичной сортировкой. Недостаток {{---}} она неустойчива. Псевдокод указан ниже:&lt;br /&gt;
&lt;br /&gt;
  '''function''' combSort(a):&lt;br /&gt;
       k = 1.3&lt;br /&gt;
       jump = n&lt;br /&gt;
       '''bool''' swapped = ''true''&lt;br /&gt;
       '''while''' jump &amp;gt; 1 '''and''' swapped&lt;br /&gt;
           '''if''' jump &amp;gt; 1&lt;br /&gt;
               jump /= k&lt;br /&gt;
           swapped = ''false''&lt;br /&gt;
           '''for''' i = 0 '''to''' size - jump - 1&lt;br /&gt;
               '''if''' a[i + jump] &amp;lt; a[i]&lt;br /&gt;
                   swap(a[i], a[i + jump])&lt;br /&gt;
                   swapped = ''true''&lt;br /&gt;
Пояснения: Изначально расстояние между сравниваемыми элементами равно &amp;lt;tex&amp;gt; n/k &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; k =1{.}3 &amp;lt;/tex&amp;gt; {{---}} оптимальное число для этого алгоритма. Сортируем массив по этому расстоянию, потом уменьшаем его по этому же правилу. Когда  расстояние между сравниваемыми элементами достигает единицы, массив досортировывается обычным пузырьком.&lt;br /&gt;
&lt;br /&gt;
=== Сортировка перемешиванием  ===&lt;br /&gt;
'''Сортировка перемешиванием''' (англ. ''cocktail sort''), также известная как '''Шейкерная сортировка'''   {{---}} разновидность пузырьковой сортировки, сортирующая массив в двух направлениях на каждой итерации. В среднем, сортировка перемешиванием работает в два раза быстрее пузырька. Сложность  {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;, но стремится она к &amp;lt;tex&amp;gt; O(k \cdot n) &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} максимальное расстояние элемента в неотсортированном массиве от его позиции в отсортированном массиве. Псевдокод указан ниже:&lt;br /&gt;
&lt;br /&gt;
  '''function''' shakerSort(a):&lt;br /&gt;
      begin = -1&lt;br /&gt;
      end = n - 2&lt;br /&gt;
      '''while''' swapped&lt;br /&gt;
        swapped = ''false''   &lt;br /&gt;
        begin++&lt;br /&gt;
        '''for''' i = begin '''to''' end &lt;br /&gt;
          '''if''' a[i] &amp;gt; a[i + 1] &lt;br /&gt;
             swap(a[i], a[i + 1])&lt;br /&gt;
             swapped = ''true''    &lt;br /&gt;
        '''if''' swapped = false &lt;br /&gt;
          '''break'''    &lt;br /&gt;
        swapped = ''false'' &lt;br /&gt;
        end--&lt;br /&gt;
        '''for''' i = end '''downto''' begin&lt;br /&gt;
           '''if''' a[i] &amp;gt; a[i + 1] &lt;br /&gt;
             swap(a[i], a[i + 1])&lt;br /&gt;
             swapped = ''true''&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Сортировка выбором]]&lt;br /&gt;
* [[Сортировка вставками]]&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Сортировка слиянием]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Bubble_sort Сортировка пузырьком {{---}} Википедия]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/sorts/quadratic-2010 Визуализатор]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Odd%E2%80%93even_sort  Сортировка чет-нечет {{---}} Википедия]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Comb_sort Сортировка расческой {{---}} Википедия]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Cocktail_sort Сортировка перемешиванием {{---}} Википедия]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;/div&gt;</summary>
		<author><name>94.26.129.35</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%91%D0%B0%D1%80%D1%80%D0%BE%D1%83%D0%B7%D0%B0-%D0%A3%D0%B8%D0%BB%D0%B5%D1%80%D0%B0&amp;diff=35218</id>
		<title>Преобразование Барроуза-Уилера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%91%D0%B0%D1%80%D1%80%D0%BE%D1%83%D0%B7%D0%B0-%D0%A3%D0%B8%D0%BB%D0%B5%D1%80%D0%B0&amp;diff=35218"/>
				<updated>2014-01-06T12:35:59Z</updated>
		
		<summary type="html">&lt;p&gt;94.26.129.35: /* Описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Определение ==&lt;br /&gt;
&lt;br /&gt;
'''Преобразование Барроуза {{---}} Уилера''' {{---}} алгоритм, используемый для предварительной обработки данных перед сжатием, разработанный для улучшения эффективности последующего кодирования. Преобразование Барроуза {{---}} Уилера меняет порядок символов во входной строке таким образом, что повторяющиеся подстроки образуют на выходе идущие подряд последовательности одинаковых символов.&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Преобразование выполняется в три этапа. &lt;br /&gt;
* Cоставляется таблица всех циклических сдвигов входной строки.&lt;br /&gt;
* Производится лексикографическая (в алфавитном порядке) сортировка строк таблицы.&lt;br /&gt;
* В качестве выходной строки выбрается последний столбец таблицы преобразования и номер строки, совпадающей с исходной.&lt;br /&gt;
&lt;br /&gt;
== Пример работы алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Пусть нам дана исходная строка &amp;lt;tex&amp;gt;s = &amp;lt;/tex&amp;gt;''&amp;quot;ABACABA&amp;quot;''. &lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;4&amp;quot;|Трансформация&lt;br /&gt;
|-&lt;br /&gt;
! Вход || Все&amp;lt;br /&amp;gt;Перестановки || Сортировка&amp;lt;br /&amp;gt;Строк || Выход&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA&amp;lt;/font&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA&amp;lt;/font&amp;gt;&lt;br /&gt;
 BACABAA&lt;br /&gt;
 ACABAAB&lt;br /&gt;
 CABAABA&lt;br /&gt;
 ABAABAC&lt;br /&gt;
 BAABACA&lt;br /&gt;
 AABACAB&lt;br /&gt;
|&lt;br /&gt;
 AABACAB&lt;br /&gt;
 ABAABAC&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA&amp;lt;/font&amp;gt;&lt;br /&gt;
 ACABAAB&lt;br /&gt;
 BAABACA&lt;br /&gt;
 BACABAA&lt;br /&gt;
 CABAABA &lt;br /&gt;
|&lt;br /&gt;
 BCABAAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Результат можно записать так: &amp;lt;tex&amp;gt;BWT(s)=&amp;lt;/tex&amp;gt;(''&amp;quot;BCABAAA&amp;quot;'', 3), где 3 {{---}} это номер исходной строки в отсортированной матрице, так как он нужен для обратного преобразования. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Следует заметить, что иногда в исходной строке приводится, так называемый, символ конца строки ''$'', который в преобразовании будет считаться последним (максимальным) символом, тогда сохранение номера исходной строки не требуется.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть нам дана исходная строка &amp;lt;tex&amp;gt;s = &amp;lt;/tex&amp;gt;''&amp;quot;ABACABA$&amp;quot;''.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;4&amp;quot;|Трансформация&lt;br /&gt;
|-&lt;br /&gt;
! Вход || Все&amp;lt;br /&amp;gt;Перестановки || Сортировка&amp;lt;br /&amp;gt;Строк || Выход&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA$&amp;lt;/font&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA$&amp;lt;/font&amp;gt;&lt;br /&gt;
 BACABA$A&lt;br /&gt;
 ACABA$AB&lt;br /&gt;
 CABA$ABA&lt;br /&gt;
 ABA$ABAC&lt;br /&gt;
 BA$ABACA&lt;br /&gt;
 A$ABACAB&lt;br /&gt;
 $ABACABA&lt;br /&gt;
&lt;br /&gt;
|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA$&amp;lt;/font&amp;gt;&lt;br /&gt;
 ABA$ABAC&lt;br /&gt;
 ACABA$AB&lt;br /&gt;
 A$ABACAB&lt;br /&gt;
 BACABA$A&lt;br /&gt;
 BA$ABACA&lt;br /&gt;
 CABA$ABA &lt;br /&gt;
 $ABACABA&lt;br /&gt;
|&lt;br /&gt;
 $CBBAAAA&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При аналогичном вышеприведённом преобразовании та строчка в матрице, которая будет заканчиваться на символ конца строки и будет исходной: (''&amp;quot;ABACABA$&amp;quot;''). Тогда результат можно записать так: &amp;lt;tex&amp;gt;BWT(s)=&amp;lt;/tex&amp;gt;''&amp;quot;$CBBAAAA&amp;quot;''.&lt;br /&gt;
&lt;br /&gt;
== Обратное преобразование ==&lt;br /&gt;
&lt;br /&gt;
===Наивный алгоритм===&lt;br /&gt;
&lt;br /&gt;
Пусть нам дано: &amp;lt;tex&amp;gt;BWT(s)=&amp;lt;/tex&amp;gt;(''&amp;quot;BCABAAA&amp;quot;'', 3). Тогда выпишем в столбик нашу преобразованную последовательность символов ''&amp;quot;BCABAAA&amp;quot;''. Запишем её как последний столбик предыдущей матрицы (при прямом преобразовании Барроуза {{---}} Уилера), при этом все предыдущие столбцы оставляем пустыми. Далее построчно отсортируем матрицу, затем в предыдущий столбец запишем ''&amp;quot;BCABAAA&amp;quot;''. Опять построчно отсортируем матрицу. Продолжая таким образом, можно восстановить полный список всех циклических перестановок строки, которую нам надо найти. Выстроив полный отсортированный список перестановок, выберем строку с номером, который нам был изначально дан. В итоге мы получим искомую строку.&lt;br /&gt;
Алгоритм обратного преобразования описан в таблице ниже:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;8&amp;quot;| Обратное преобразование&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;8&amp;quot;| Вход&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot; colspan=&amp;quot;8&amp;quot;|&lt;br /&gt;
 BCABAAA&lt;br /&gt;
|-&lt;br /&gt;
! Добавление 1 || Сортировка 1 || Добавление 2 || Сортировка 2 || Добавление 3 || Сортировка 3 || Добавление 4 &lt;br /&gt;
|-align=&amp;quot;right&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
 B&lt;br /&gt;
 C&lt;br /&gt;
 A&lt;br /&gt;
 B&lt;br /&gt;
 A&lt;br /&gt;
 A&lt;br /&gt;
 A&lt;br /&gt;
|&lt;br /&gt;
 A&lt;br /&gt;
 A&lt;br /&gt;
 A&lt;br /&gt;
 A&lt;br /&gt;
 B&lt;br /&gt;
 B&lt;br /&gt;
 C&lt;br /&gt;
|&lt;br /&gt;
 BA&lt;br /&gt;
 CA&lt;br /&gt;
 AA&lt;br /&gt;
 BA&lt;br /&gt;
 AB&lt;br /&gt;
 AB&lt;br /&gt;
 AC&lt;br /&gt;
|&lt;br /&gt;
 AA&lt;br /&gt;
 AB&lt;br /&gt;
 AB&lt;br /&gt;
 AC&lt;br /&gt;
 BA&lt;br /&gt;
 BA&lt;br /&gt;
 CA&lt;br /&gt;
|&lt;br /&gt;
 BAA&lt;br /&gt;
 CAB&lt;br /&gt;
 AAB&lt;br /&gt;
 BAC&lt;br /&gt;
 ABA&lt;br /&gt;
 ABA&lt;br /&gt;
 ACA&lt;br /&gt;
|&lt;br /&gt;
 AAB&lt;br /&gt;
 ABA&lt;br /&gt;
 ABA&lt;br /&gt;
 ACA&lt;br /&gt;
 BAA&lt;br /&gt;
 BAC&lt;br /&gt;
 CAB&lt;br /&gt;
|&lt;br /&gt;
 BAAB&lt;br /&gt;
 CABA&lt;br /&gt;
 AABA&lt;br /&gt;
 BACA&lt;br /&gt;
 ABAA&lt;br /&gt;
 ABAC&lt;br /&gt;
 ACAB&lt;br /&gt;
|-&lt;br /&gt;
! Сортировка 4 || Добавление 5 || Сортировка 5 || Добавление 6 || Сортировка 6 || Добавление 7 || Сортировка 7&lt;br /&gt;
&lt;br /&gt;
|-align=&amp;quot;right&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
 AABA&lt;br /&gt;
 ABAA&lt;br /&gt;
 ABAC&lt;br /&gt;
 ACAB&lt;br /&gt;
 BAAB&lt;br /&gt;
 BACA&lt;br /&gt;
 CABA&lt;br /&gt;
|&lt;br /&gt;
 BAABA&lt;br /&gt;
 CABAA&lt;br /&gt;
 AABAC&lt;br /&gt;
 BACAB&lt;br /&gt;
 ABAAB&lt;br /&gt;
 ABACA&lt;br /&gt;
 ACABA&lt;br /&gt;
|&lt;br /&gt;
 AABAC&lt;br /&gt;
 ABAAB&lt;br /&gt;
 ABACA&lt;br /&gt;
 ACABA&lt;br /&gt;
 BAABA&lt;br /&gt;
 BACAB&lt;br /&gt;
 CABAA&lt;br /&gt;
|&lt;br /&gt;
 BAABAC&lt;br /&gt;
 CABAAB&lt;br /&gt;
 AABACA&lt;br /&gt;
 BACABA&lt;br /&gt;
 ABAABA&lt;br /&gt;
 ABACAB&lt;br /&gt;
 ACABAA&lt;br /&gt;
|&lt;br /&gt;
 AABACA&lt;br /&gt;
 ABAABA&lt;br /&gt;
 ABACAB&lt;br /&gt;
 ACABAA&lt;br /&gt;
 BAABAC&lt;br /&gt;
 BACABA&lt;br /&gt;
 CABAAB&lt;br /&gt;
|&lt;br /&gt;
 BAABACA&lt;br /&gt;
 CABAABA&lt;br /&gt;
 AABACAB&lt;br /&gt;
 BACABAA&lt;br /&gt;
 ABAABAC&lt;br /&gt;
 ABACABA&lt;br /&gt;
 ACABAAB&lt;br /&gt;
|&lt;br /&gt;
 AABACAB&lt;br /&gt;
 ABAABAC&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA&amp;lt;/font&amp;gt;&lt;br /&gt;
 ACABAAB&lt;br /&gt;
 BAABACA&lt;br /&gt;
 BACABAA&lt;br /&gt;
 CABAABA&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
!colspan=&amp;quot;8&amp;quot;| Результат&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot; colspan=&amp;quot;8&amp;quot;|&lt;br /&gt;
 &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;ABACABA&amp;lt;/font&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Следует также заметить, что если нам было бы дано &amp;lt;tex&amp;gt;BWT(s)=&amp;lt;/tex&amp;gt;''&amp;quot;$CBBAAAA&amp;quot;'', то мы также получили бы нашу исходную строку, только с символом конца строки ''$'' на конце: ''ABACABA$''.&lt;br /&gt;
&lt;br /&gt;
Как несложно посчитать сложность данного алгоритма &amp;lt;tex&amp;gt;O(N^3logN) &amp;lt;/tex&amp;gt;, также он требует &amp;lt;tex&amp;gt;O(N^2)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
===Оптимизация===&lt;br /&gt;
&lt;br /&gt;
Однако, данный алгоритм можно оптимизировать. Заметим, что при каждом проявлении неизвестного столбца выполнялись одни и те же действия. Мы приписывали новый столбец и сортировали имеющиеся данные. На каждом шагу мы к строке, которая находилась на &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;-ом месте приписываем в начало &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; -ый элемент столбца входных данных. Пусть изначально мы знаем каким по порядку является приписанный нами в начало символ (то есть каким по порядку в столбце). И конечно же мы знаем исходя из предыдущего шага какое место занимала наша строка без этого первого символа (&amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; -ое). Тогда несложно заметить, что при выполнении такой операции строка с номером &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; всегда будет перемещаться на позицию с номером &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 {| border=&amp;quot;1&amp;quot;&lt;br /&gt;
  |0||а||&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;||р||9&lt;br /&gt;
  |-&lt;br /&gt;
  |1||а||||д||7&lt;br /&gt;
  |-&lt;br /&gt;
  |2||а|| ||a||0&lt;br /&gt;
  |-&lt;br /&gt;
  |3||а|| ||к||8&lt;br /&gt;
  |-&lt;br /&gt;
  |4||а|| ||р||10&lt;br /&gt;
  |-&lt;br /&gt;
  |5||б|| ||a||1&lt;br /&gt;
  |-&lt;br /&gt;
  |6||б|| ||a||2&lt;br /&gt;
  |-&lt;br /&gt;
  |7||д|| ||a||3&lt;br /&gt;
  |-&lt;br /&gt;
  |8||к|| ||a||4&lt;br /&gt;
  |-&lt;br /&gt;
  |9||р|| ||б||5&lt;br /&gt;
  |-&lt;br /&gt;
  |10||р|| ||б||6&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
Здесь слева это отсортированный данный столбец, чтобы мы знали какое место в лексикографическом порядке занимает приписываемый нами символ среди всех элементов данного нам изначально столбца. Справа - изначально данный столбец и соответствующее ему число. Поскольку мы в нашем алгоритме новый столбец приписываем в начало, то мы из состояния &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; (левый столбец) переходим в состояние &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt; (правый). Для того, чтобы восстановить строку, нам необходимо от последней такой цифры по пути из &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; восстановить строку.&lt;br /&gt;
{|&lt;br /&gt;
 |&lt;br /&gt;
 {| border=&amp;quot;1&amp;quot;&lt;br /&gt;
 |6&lt;br /&gt;
 |→&lt;br /&gt;
 |10&lt;br /&gt;
 |→&lt;br /&gt;
 |4 &lt;br /&gt;
 |→&lt;br /&gt;
 |8&lt;br /&gt;
 |→ &lt;br /&gt;
 |3&lt;br /&gt;
 |→&lt;br /&gt;
 |7&lt;br /&gt;
 |→&lt;br /&gt;
 |1&lt;br /&gt;
 |→&lt;br /&gt;
 |5&lt;br /&gt;
 |→&lt;br /&gt;
 |9&lt;br /&gt;
 |→&lt;br /&gt;
 |0&lt;br /&gt;
 |→&lt;br /&gt;
 |2&lt;br /&gt;
 |-&lt;br /&gt;
 |а&lt;br /&gt;
 |&lt;br /&gt;
 |б&lt;br /&gt;
 |&lt;br /&gt;
 |р&lt;br /&gt;
 |&lt;br /&gt;
 |а&lt;br /&gt;
 |&lt;br /&gt;
 |к&lt;br /&gt;
 |&lt;br /&gt;
 |а&lt;br /&gt;
 |&lt;br /&gt;
 |д&lt;br /&gt;
 |&lt;br /&gt;
 |а&lt;br /&gt;
 |&lt;br /&gt;
 |б&lt;br /&gt;
 |&lt;br /&gt;
 |р&lt;br /&gt;
 |&lt;br /&gt;
 |а&lt;br /&gt;
|}&lt;br /&gt;
===Сложность оптимизированного алгоритма===&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt;O(NlogN)&amp;lt;/tex&amp;gt; действий и требует &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; памяти. Однако, если размер алфавита не очень большой, то для выяснения первого столбца матрицы можно использовать сортировку подсчетом, в этом случае алгоритм работает за &amp;lt;tex&amp;gt;O(N+M)&amp;lt;/tex&amp;gt; действий и требует &amp;lt;tex&amp;gt;O(N+M)&amp;lt;/tex&amp;gt; памяти, где &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; — размер алфавита.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод оптимизированного алгоритма===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; N &amp;lt;/tex&amp;gt; — количество символов во входной строке, &amp;lt;tex&amp;gt; M &amp;lt;/tex&amp;gt; — количество символов в алфавите, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; — номер исходной строки в матрице перестановок, &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; — входящая строка, &amp;lt;tex&amp;gt; count &amp;lt;/tex&amp;gt;  — массив для сортировки подсчетом, &amp;lt;tex&amp;gt; t &amp;lt;/tex&amp;gt; — вектор обратного преобразования, &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; — номер данной нам строки в таблице.&lt;br /&gt;
&lt;br /&gt;
 // Cчитаем частоты символов&lt;br /&gt;
 for i = 0 .. M &lt;br /&gt;
   count[i] = 0&lt;br /&gt;
 for i = 0 .. N &lt;br /&gt;
   count[s[i]]++&lt;br /&gt;
 // Упорядочиваем символы, чтобы получить первый столбец исходной матрицы&lt;br /&gt;
 // count[i] указывает на первую позицию символа i в первом столбце&lt;br /&gt;
 sum = 0&lt;br /&gt;
 for i = 0 .. M&lt;br /&gt;
   sum = sum + count[i]&lt;br /&gt;
   count[i] = sum - count[i]&lt;br /&gt;
 // Cоздаем вектор обратного преобразования&lt;br /&gt;
 for i = 0 .. N&lt;br /&gt;
   t[count[s[i]]] = i&lt;br /&gt;
   count[s[i]]++&lt;br /&gt;
 // И восстанавливаем исходный текст&lt;br /&gt;
 j = t[x]&lt;br /&gt;
 for i = 0 .. N&lt;br /&gt;
   print(s[j])&lt;br /&gt;
   j = t[j]&lt;br /&gt;
&lt;br /&gt;
===Доказательство корректности===&lt;br /&gt;
&lt;br /&gt;
Пусть текст &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; состоит из &amp;lt;tex&amp;gt;N + 1&amp;lt;/tex&amp;gt; символов, занумерованных с нуля: &amp;lt;tex&amp;gt;T[0..N]&amp;lt;/tex&amp;gt;. Буквы &amp;lt;tex&amp;gt;T[i]&amp;lt;/tex&amp;gt; принадлежат некоторому алфавиту &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;. Лексикографический порядок (строгий) на строках из алфавита &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; будем обозначать &amp;lt;tex&amp;gt;\preceq (\prec)&amp;lt;/tex&amp;gt;. Обозначим через &amp;lt;tex&amp;gt;S_{k}T&amp;lt;/tex&amp;gt; циклический сдвиг текста &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; символов влево:&lt;br /&gt;
:{|&lt;br /&gt;
&amp;lt;tex&amp;gt; S_{k}T = T[(j + k) (mod\ N + 1)] &amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Существует перестановка &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; чисел &amp;lt;tex&amp;gt;\{0, ..., N\}&amp;lt;/tex&amp;gt;, которая удовлетворяет условию: &lt;br /&gt;
:{|&lt;br /&gt;
&amp;lt;tex&amp;gt; S_{p(i)}T \preceq S_{p(i + 1)}T,\ i = 0, ..., N - 1\ \ \textbf{(1)}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Преобразование Барроуза-Уилера текста &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; есть текст &amp;lt;tex&amp;gt;B[0..N] = BW(T)&amp;lt;/tex&amp;gt;, буквы которого заданы соотношением:&lt;br /&gt;
:{|&lt;br /&gt;
&amp;lt;tex&amp;gt;B[i] = S_{p(i)}T[N]&amp;lt;/tex&amp;gt;, другими словами &amp;lt;tex&amp;gt;B[i] = S_{p(i) - 1}T[0] = T[(p(i) - 1) (mod\ N + 1)] \ \ \textbf{(2)}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt; {{---}} перестановка чисел &amp;lt;tex&amp;gt;\{0, ..., N\}&amp;lt;/tex&amp;gt;, удовлетворяющая условию:&lt;br /&gt;
:{|&lt;br /&gt;
&amp;lt;tex&amp;gt;B_{\sigma(i)} \preceq B_{\sigma(i + 1)}&amp;lt;/tex&amp;gt;, при &amp;lt;tex&amp;gt;i = 0, ..., N - 1\ \ \textbf{(3)}&amp;lt;/tex&amp;gt;,&lt;br /&gt;
|}&lt;br /&gt;
и в случае равенства &amp;lt;tex&amp;gt;B_{\sigma(i)}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B_{\sigma(i + 1)}&amp;lt;/tex&amp;gt; выполнено {{---}} &amp;lt;tex&amp;gt;\sigma(i) &amp;lt; \sigma(i + 1)&amp;lt;/tex&amp;gt;. Перестановка однозначно определяется текстом &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и ее можно посчитать за &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt;, используя сортировку подсчетом. Рассмотрим перестановку &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt; как отображение &amp;lt;tex&amp;gt;\sigma : \{0, ..., N\} \to \{0, ..., N\}&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;\sigma^{k}&amp;lt;/tex&amp;gt; копмозиция &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отображений &amp;lt;tex&amp;gt;\sigma^{k} = \sigma^{k - 1} \circ \sigma&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\sigma^{1} = \sigma, \sigma^{0} \equiv i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
&lt;br /&gt;
''При всех &amp;lt;tex&amp;gt;m = 1, ..., N + 1&amp;lt;/tex&amp;gt; верны утверждения,&lt;br /&gt;
:&amp;lt;tex&amp;gt;B_{\sigma(i)}...B_{\sigma^{m}(i)} \preceq B_{\sigma(i + 1)}...B_{\sigma^{m}(i + 1)}&amp;lt;/tex&amp;gt;, при &amp;lt;tex&amp;gt;i = 0, ..., N - 1\ \ \textbf{(4)}&amp;lt;/tex&amp;gt;&lt;br /&gt;
:&amp;lt;tex&amp;gt;B_iB_{\sigma(i)}...B_{\sigma^{m - 1}(i)} = S_{p(i) - 1}T[0..m - 1]&amp;lt;/tex&amp;gt;, при &amp;lt;tex&amp;gt;i = 0, ..., N\ \ \textbf{(5)}&amp;lt;/tex&amp;gt;&lt;br /&gt;
''&lt;br /&gt;
&lt;br /&gt;
|proof=&lt;br /&gt;
&lt;br /&gt;
Если лексикографически отсортировать буквы последнего столбца и поместить их в первый столбец, то получится таблица&lt;br /&gt;
&lt;br /&gt;
| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Таблица&lt;br /&gt;
|-&lt;br /&gt;
|a||b||c&lt;br /&gt;
|-&lt;br /&gt;
|a||b||c&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
&lt;br /&gt;
''Для восстановления исходного текста &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; из преобразования &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; достаточно знать число &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt;, отвечающее условию &amp;lt;tex&amp;gt;p(I) = 0&amp;lt;/tex&amp;gt;, другими словами &amp;lt;tex&amp;gt;S_{p(I)}T = T&amp;lt;/tex&amp;gt;.''&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Дополнительно ==&lt;br /&gt;
&lt;br /&gt;
* bzip2 использует преобразование Барроуза {{---}} Уилера для превращения последовательностей многократно чередующихся символов в строки одинаковых символов, затем применяет преобразование MTF (англ. move-to-front), и в конце кодирование Хаффмана.&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%91%D0%B0%D1%80%D1%80%D0%BE%D1%83%D0%B7%D0%B0_%E2%80%94_%D0%A3%D0%B8%D0%BB%D0%B5%D1%80%D0%B0 Преобразование Барроуза {{---}} Уилера (Википедия)]&lt;br /&gt;
&lt;br /&gt;
*[http://www.cs.karelia.ru/~aborod/inf/2010/schedule.php.ru Преобразование Барроуза {{---}} Уилера (cs.karelia.ru)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>94.26.129.35</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%80%D1%8E%D0%BA%D0%B7%D0%B0%D0%BA%D0%B5&amp;diff=33903</id>
		<title>Задача о рюкзаке</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%80%D1%8E%D0%BA%D0%B7%D0%B0%D0%BA%D0%B5&amp;diff=33903"/>
				<updated>2013-12-04T12:23:22Z</updated>
		
		<summary type="html">&lt;p&gt;94.26.129.35: /* Неограниченный рюкзак */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о рюкзаке'''(''англ. Knapsack problem'') — дано &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; предметов, &amp;lt;tex&amp;gt;n_i&amp;lt;/tex&amp;gt; предмет имеет массу &amp;lt;tex&amp;gt; w_i &amp;gt; 0&amp;lt;/tex&amp;gt; и стоимость &amp;lt;tex&amp;gt; p_i &amp;gt; 0&amp;lt;/tex&amp;gt;. Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt; (вместимость рюкзака), а суммарная стоимость была максимальна.&lt;br /&gt;
&lt;br /&gt;
== Формулировка задачи ==&lt;br /&gt;
&lt;br /&gt;
Дано &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; предметов, &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt; - вместимость рюкзака, &amp;lt;tex&amp;gt;w=\{w_{1},w_{2},...,w_{N}\}&amp;lt;/tex&amp;gt; — соответствующий ему набор положительных целых весов, &amp;lt;tex&amp;gt;p=\{p_{1},p_{2},...,p_{N}\}&amp;lt;/tex&amp;gt; — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин &amp;lt;tex&amp;gt;B=\{b_{1},b_{2},...,b_{N}\}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;b_{i} = 1 &amp;lt;/tex&amp;gt;, если предмет &amp;lt;tex&amp;gt;n_i&amp;lt;/tex&amp;gt; включен в набор, &amp;lt;tex&amp;gt; b_{i} = 0 &amp;lt;/tex&amp;gt;, если предмет &amp;lt;tex&amp;gt;n_i&amp;lt;/tex&amp;gt; не включен, и такой что:&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;tex&amp;gt;b_{1} w_{1}+ ... + b_{N} w_{N} \le W&amp;lt;/tex&amp;gt;&lt;br /&gt;
#&amp;lt;tex&amp;gt;b_{1} p_{1}+ ... + b_{N} p_{N} &amp;lt;/tex&amp;gt; максимальна.&lt;br /&gt;
&lt;br /&gt;
== Варианты решения ==&lt;br /&gt;
&lt;br /&gt;
Задачу о рюкзаке можно решить несколькими способами:&lt;br /&gt;
&lt;br /&gt;
* Перебирать все подмножества набора из N предметов. Сложность такого решения &amp;lt;tex&amp;gt;O({2^{N}})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Методом [[Meet-in-the-middle|Meet-in-the-middle]]. Сложность решения &amp;lt;tex&amp;gt; O({2^{N/2}}\times{N}) &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Метод динамического программирования. Сложность - &amp;lt;tex&amp;gt;O(N \times W)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Метод динамического программирования ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;A(k, s)&amp;lt;/tex&amp;gt; есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, если можно использовать только первые &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; предметов, то есть &amp;lt;tex&amp;gt;\{n_1,n_2,...,n_k\}&amp;lt;/tex&amp;gt;, назовем этот набор допустимых предметов для &amp;lt;tex&amp;gt;A(k,s)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;A(k, 0) = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;A(0, s) = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;tex&amp;gt;A(k, s)&amp;lt;/tex&amp;gt;. Возможны 2 варианта:&lt;br /&gt;
&lt;br /&gt;
#Если предмет &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; не попал в рюкзак. Тогда &amp;lt;tex&amp;gt;A(k, s)&amp;lt;/tex&amp;gt; равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов &amp;lt;tex&amp;gt;\{n_1,n_2,...,n_{k-1}\}&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;A(k,s) = A(k-1, s)&amp;lt;/tex&amp;gt;&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; попал в рюкзак. Тогда &amp;lt;tex&amp;gt;A(k, s)&amp;lt;/tex&amp;gt; равно максимальной стоимости рюкзака, где вес &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; уменьшаем на вес &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; -ого предмета и набор допустимых предметов &amp;lt;tex&amp;gt;\{n_1,n_2,...,n_{k-1}\}&amp;lt;/tex&amp;gt; плюс стоимость &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;A(k-1, s-w_k) + p_k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть: &lt;br /&gt;
&lt;br /&gt;
#&amp;lt;tex&amp;gt;A(k,s) = A(k-1, s)&amp;lt;/tex&amp;gt;&lt;br /&gt;
#&amp;lt;tex&amp;gt;A(k,s) = A(k-1, s-w_k) + p_k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выберем из этих двух значений максимальное:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;A(k,s) = max(A(k-1,s), A(k-1,s-w_{k}) + p_{k})&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Стоимость искомого набора равна &amp;lt;tex&amp;gt;A(N,W)&amp;lt;/tex&amp;gt;, так как нужно найти максимальную стоимость рюкзака, где все предметы допустимы и вместимость рюкзака &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Восстановим набор предметов, входящих в рюкзак'''&lt;br /&gt;
&lt;br /&gt;
Будем определять, входит ли &amp;lt;tex&amp;gt;n_i&amp;lt;/tex&amp;gt; предмет в искомый набор. Начинаем с элемента &amp;lt;tex&amp;gt;A(i,w)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;i = N&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w = W&amp;lt;/tex&amp;gt;. Для этого сравниваем &amp;lt;tex&amp;gt;A(i,w)&amp;lt;/tex&amp;gt; со следующими значениями:&lt;br /&gt;
&lt;br /&gt;
#Максимальная стоимость рюкзака с такой же вместимостью и набором допустимых предметов &amp;lt;tex&amp;gt;\{n_1,n_2,...,n_{i-1}\}&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;A(i-1, w)&amp;lt;/tex&amp;gt;&lt;br /&gt;
#Максимальная стоимость рюкзака с вместимостью на &amp;lt;tex&amp;gt;w_i&amp;lt;/tex&amp;gt; меньше и набором допустимых предметов &amp;lt;tex&amp;gt;\{n_1,n_2,...,n_{i-1}\}&amp;lt;/tex&amp;gt; плюс стоимость &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;A(i-1, w-w_i)+p_i&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что при построении &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; мы выбирали максимум из этих значений и записывали в &amp;lt;tex&amp;gt;A(i, w)&amp;lt;/tex&amp;gt;. Тогда будем сравнивать &amp;lt;tex&amp;gt;A(i, w)&amp;lt;/tex&amp;gt; c &amp;lt;tex&amp;gt;A(i-1, w)&amp;lt;/tex&amp;gt;, если равны, тогда &amp;lt;tex&amp;gt;n_i&amp;lt;/tex&amp;gt; не входит в искомый набор, иначе входит.&lt;br /&gt;
&lt;br /&gt;
== Реализация ==&lt;br /&gt;
Сначала генерируем &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 for i = 0..W&lt;br /&gt;
   A[0][i] = 0;&lt;br /&gt;
 for i = 0..N&lt;br /&gt;
   A[i][0] = 0;   //Первые элементы приравниваем к 0&lt;br /&gt;
 for k = 1..N               &lt;br /&gt;
   for s = 0..W   //Перебираем для каждого k все вместисмости &lt;br /&gt;
     if s &amp;gt;= w[k]    //Если текущий предмет вмещается в рюкзак&lt;br /&gt;
       A[k][s] = max(A[k-1][s], A[k-1][s-w[k]]+p[k]); //выбираем класть его или нет&lt;br /&gt;
     else &lt;br /&gt;
       A[k][s] = A[k-1][s];             //иначе, не кладем&lt;br /&gt;
&lt;br /&gt;
Затем найдем набор &amp;lt;tex&amp;gt;ans&amp;lt;/tex&amp;gt; предметов, входящих в рюкзак, рекурсивной функцией:&lt;br /&gt;
&lt;br /&gt;
 findAns(k, s)&lt;br /&gt;
   if A[k][s] == 0 &lt;br /&gt;
     return;&lt;br /&gt;
   if A[k-1][s] == A[k][s]&lt;br /&gt;
     findAns(k-1, s);&lt;br /&gt;
   else &lt;br /&gt;
     findAns(k-1, s - w[k]);&lt;br /&gt;
     ans.push(k);&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;tex&amp;gt;O(N \times W)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;W = 13, N = 5&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;w_{1} = 3, p_{1} = 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;w_{2} = 4, p_{2} = 6 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;w_{3} = 5, p_{3} = 4 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;w_{4} = 8, p_{4} = 7 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;w_{5} = 9, p_{5} = 6 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Knapsack problem0.png]]&lt;br /&gt;
&lt;br /&gt;
Числа от 0 до 13 в первой строчке обозначают вместимость рюкзака.&lt;br /&gt;
&lt;br /&gt;
В первой строке как только вместимость рюкзака &amp;lt;tex&amp;gt;n \ge 3&amp;lt;/tex&amp;gt;, добавляем в рюкзак 1 предмет.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим &amp;lt;tex&amp;gt;k = 3&amp;lt;/tex&amp;gt;, при каждом &amp;lt;tex&amp;gt;s \ge 5 (&amp;lt;/tex&amp;gt;так как &amp;lt;tex&amp;gt;w_3 = 5)&amp;lt;/tex&amp;gt; сравниваем &amp;lt;tex&amp;gt;A[k-1][s]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;A[k-1][s-w_3]+p_3&amp;lt;/tex&amp;gt; и записываем в &amp;lt;tex&amp;gt;A[k][s]&amp;lt;/tex&amp;gt; стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимости третьего предмета плюс стоимость рюкзака с вместимостью на &amp;lt;tex&amp;gt;w_3&amp;lt;/tex&amp;gt; меньше.     &lt;br /&gt;
&lt;br /&gt;
Максимальная стоимость рюкзака находится в &amp;lt;tex&amp;gt;A(5, 13)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.'''&lt;br /&gt;
&lt;br /&gt;
Начиная с &amp;lt;tex&amp;gt;A(5, 13)&amp;lt;/tex&amp;gt; восстанавливаем ответ.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Задача о рюкзаке3.png]]&lt;br /&gt;
&lt;br /&gt;
Таким образом, в набор входит &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; предмет.&lt;br /&gt;
&lt;br /&gt;
Стоимость рюкзака &amp;lt;tex&amp;gt;= 6 + 7 = 13&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вес рюкзака &amp;lt;tex&amp;gt;= 4 + 8 = 12&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Другие задачи семейства=&lt;br /&gt;
==Ограниченный рюкзак ==&lt;br /&gt;
'''Ограниченный рюкзак''' (англ. ''Bounded Knapsack Problem'') - обобщение классической задачи, когда любой предмет может быть взят некоторое количество раз.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' Вор грабит склад. Он может унести ограниченный вес, каждый товар на складе содержится в определенном ограниченном количестве. Нужно унести предметов на максимальную сумму.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Каждый предмет может быть выбран ограниченное &amp;lt;tex&amp;gt;b_i&amp;lt;/tex&amp;gt; число раз.&lt;br /&gt;
Задача выбрать число &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; предметов каждого типа так, чтобы&lt;br /&gt;
&lt;br /&gt;
* максимизировать общую стоимость: &amp;lt;tex&amp;gt;\sum_{i=1}^N p_ix_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
* выполнялось условие совместности: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i \le W&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;tex&amp;gt; x_i \in (0,1,...,b_i)&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
При небольших &amp;lt;tex&amp;gt;b_i&amp;lt;/tex&amp;gt; решается сведением к классической задаче о рюкзаке. В иных случаях:&lt;br /&gt;
* Методом ветвей и границ.&lt;br /&gt;
* Методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
===Метод динамического программирования===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt; максимальная стоимость любого возможного числа предметов типов от 1 до &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, суммарным весом до &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заполним &amp;lt;tex&amp;gt;d(0,c)&amp;lt;/tex&amp;gt; нулями.&lt;br /&gt;
&lt;br /&gt;
Тогда меняя i от 1 до &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt;, рассчитаем на каждом шаге &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt;, для &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; от 0 до &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;, по рекуррентной формуле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;d(i,c) = max(d(i - 1, c - lw_i) + lp_i) &amp;lt;/tex&amp;gt; по всем целым &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; из промежутка &amp;lt;tex&amp;gt; 0 \le l \le min(b_i,\lfloor c/w_i \rfloor)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если не нужно восстанавливать ответ, то можно использовать одномерный массив &amp;lt;tex&amp;gt;d(c)&amp;lt;/tex&amp;gt; вместо двумерного.&lt;br /&gt;
&lt;br /&gt;
После выполнения в &amp;lt;tex&amp;gt; d(N,W) &amp;lt;/tex&amp;gt; будет лежать максимальная стоимость предметов, помещающихся в рюкзак.&lt;br /&gt;
&lt;br /&gt;
=== Реализация ===&lt;br /&gt;
 for i = 0..W // база&lt;br /&gt;
   d[0][i] = 0;&lt;br /&gt;
 for i = 1..N             &lt;br /&gt;
   for c = 0..W   //Перебираем для каждого i, все вместимости &lt;br /&gt;
     d[i][c] = d[i - 1][c];&lt;br /&gt;
     for l = min(b[i], c / w[i]) .. 1 // ищем l для которого выполняется максимум&lt;br /&gt;
         d[i][c] =  max(d[i][c], d[i - 1][c - l * w[i]] + p[i] * l);&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;tex&amp;gt;O(NW^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Неограниченный рюкзак==&lt;br /&gt;
'''Неограниченный рюкзак''' (англ.''Unbounded Knapsack Problem'') - обобщение ограниченного рюкзака, в котором любой предмет может быть выбран любое количество раз.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' Перекупщик закупается на оптовой базе. Он может увезти ограниченное количество товара, количество товара каждого типа на базе не ограниченно. Нужно увезти товар на максимальную сумму.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Каждый предмет может быть выбран любое число раз.&lt;br /&gt;
Задача выбрать количество &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; предметов каждого типа так, чтобы&lt;br /&gt;
&lt;br /&gt;
*максимизировать общую стоимость: &amp;lt;tex&amp;gt;\sum_{i=1}^N p_ix_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
*выполнялось условие совместности: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i \le W&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;tex&amp;gt; x_i \ge 0 &amp;lt;/tex&amp;gt; целое,  для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Самые распространенные методы точного решения это:&lt;br /&gt;
* Метод ветвей и границ.&lt;br /&gt;
* Метод динамического программирования.&lt;br /&gt;
&lt;br /&gt;
===Метод динамического программирования===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt; максимальная стоимость любого количества вещей типов от 1 до &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, суммарным весом до &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; включительно.&lt;br /&gt;
&lt;br /&gt;
Заполним &amp;lt;tex&amp;gt;d(0,c)&amp;lt;/tex&amp;gt; нулями.&lt;br /&gt;
&lt;br /&gt;
Тогда меняя i от 1 до &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt;, рассчитаем на каждом шаге &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt;, для &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; от 0 до &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;, по рекуррентной формуле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
d(i,c) =&lt;br /&gt;
\begin{cases}&lt;br /&gt;
 d(i - 1, c) &amp;amp; for\ c = 0, ..., w_i - 1; \\&lt;br /&gt;
 max(d(i - 1, c), d(i, c - w_i) + p_i) &amp;amp; for\ c = w_i, ..., W; &lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После выполнения в &amp;lt;tex&amp;gt; d(N,W) &amp;lt;/tex&amp;gt; будет лежать максимальная стоимость предметов, помещающихся в рюкзак.&lt;br /&gt;
&lt;br /&gt;
Если не нужно восстанавливать ответ, то можно использовать одномерный массив &amp;lt;tex&amp;gt;d(c)&amp;lt;/tex&amp;gt; вместо двумерного и использовать формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  d(c) = max(d(c), d(c - w_i) + p_i)   &amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;tex&amp;gt;O(NW)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Непрерывный рюкзак==&lt;br /&gt;
'''Непрерывный рюкзак''' (англ. ''Continuous knapsack problem'') - вариант задачи, в котором возможно брать любою дробную часть от предмета, при этом удельная стоимость сохраняется.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' Вор грабит мясника. Суммарно он может унести ограниченный вес товаров. Вор может резать товары без ущерба к удельной стоимости. Нужно унести товара на максимальную сумму.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Задача выбрать часть &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; каждого предмета так, чтобы&lt;br /&gt;
&lt;br /&gt;
*максимизировать общую стоимость: &amp;lt;tex&amp;gt;\sum_{i=1}^N p_ix_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
*выполнялось условие совместности: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i \le W&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;tex&amp;gt; 0 \le x_i \le 1&amp;lt;/tex&amp;gt; дробное, для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Возможность брать любую часть от предмета сильно упрощает задачу. Жадный алгоритм дает оптимальное решение в данном случае.&lt;br /&gt;
&lt;br /&gt;
=== Реализация ===&lt;br /&gt;
 sort(); // сортируем в порядке убывания удельной стоимости.&lt;br /&gt;
 for i = 1..N // идем по предметам            &lt;br /&gt;
       if W &amp;gt;= w[i]    //если помещается - берем&lt;br /&gt;
        sum += p[i];&lt;br /&gt;
        W -= w[i];&lt;br /&gt;
    else&lt;br /&gt;
        sum += W / w[i] * p[i];// иначе берем сколько можно и выходим&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
==Задача о суммах подмножеств==&lt;br /&gt;
'''Задача о суммах подмножеств''' (англ. ''Subset-sum problem, Value Independent Knapsack Problem'') - задача из семейства, в которой стоимость предмета совпадает с его весом.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' В машина может увезти определенное количество груза. Нужно увезти как можно больше крупного неделимого мусора за раз.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Нужно выбрать подмножество так, чтобы сумма ближе всего к &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;, но не превысила его. Формально, нужно найти набор бинарных величин &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt;, так чтобы&lt;br /&gt;
&lt;br /&gt;
*максимизировать общую стоимость: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
*выполнялось условие совместности: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i \le W&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; x_j = 1 &amp;lt;/tex&amp;gt; если &amp;lt;tex&amp;gt; j&amp;lt;/tex&amp;gt; предмет назначен рюкзаку, иначе &amp;lt;tex&amp;gt; x_{ij} = 0 &amp;lt;/tex&amp;gt;,  для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Для решения пригодны любые методы применяемые для классической задачи, однако специализированые алгоритмы обычно более оптимальны по параметрам. Используются:&lt;br /&gt;
* Метод динамического программирования.&lt;br /&gt;
* Гибридный метод на основе динамического программирования и поиска по дереву. В худшем случае, работает за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Метод динамического программирования===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt; максимальная сумма  &amp;lt;tex&amp;gt;\le c&amp;lt;/tex&amp;gt;, подмножества взятого из &amp;lt;tex&amp;gt; 1, ...,\ i&amp;lt;/tex&amp;gt; элементов.&lt;br /&gt;
&lt;br /&gt;
Заполним &amp;lt;tex&amp;gt;d(0,c)&amp;lt;/tex&amp;gt; нулями.&lt;br /&gt;
&lt;br /&gt;
Тогда меняя i от 1 до &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt;, рассчитаем на каждом шаге &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt;, для &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; от 0 до &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;, по рекуррентной формуле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
d(i,c) =&lt;br /&gt;
\begin{cases}&lt;br /&gt;
 d(i - 1, c) &amp;amp; for\ c = 0, ..., w_i - 1; \\&lt;br /&gt;
 max(d(i - 1, c), d(i - 1, c - w_i) + w_i) &amp;amp; for\ c = w_i, ..., W; &lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После выполнения в &amp;lt;tex&amp;gt; d(N,W) &amp;lt;/tex&amp;gt; будет лежать максимальная сумма подмножества, не превышающая заданное значение.&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;tex&amp;gt;O(NW)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Задача о размене==&lt;br /&gt;
'''Задача о размене''' (англ. ''Change-Making problem'') - имеются &amp;lt;tex&amp;gt; N &amp;lt;/tex&amp;gt; неисчерпаемых типов предметов с весами &amp;lt;tex&amp;gt;w_i&amp;lt;/tex&amp;gt;.  Нужно наполнить рюкзак предметами с суммарным весом &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Часто задачу ставят как, дать сдачу наименьшим количеством монет.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Каждый предмет может быть выбран любое число раз.&lt;br /&gt;
Задача выбрать количество &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; предметов каждого типа так, чтобы&lt;br /&gt;
&lt;br /&gt;
*минимизировать количество взятых предметов: &amp;lt;tex&amp;gt;\sum_{i=1}^N x_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
*сумма весов выбранных предметов равнялась вместимости рюкзака: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_i = W&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Где &amp;lt;tex&amp;gt; x_i \ge 0 &amp;lt;/tex&amp;gt; целое,  для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Самые распространенные методы точного решения это:&lt;br /&gt;
* Метод ветвей и границ.&lt;br /&gt;
* Метод динамического программирования.&lt;br /&gt;
&lt;br /&gt;
===Метод динамического программирования===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt; минимальное число предметов, типов от 1 до &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, необходимое, чтобы заполнить рюкзак вместимостью &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d(0,0) = 0&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d(0,c) = \inf&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt;c &amp;gt; 0&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Тогда меняя i от 1 до &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt;, рассчитаем на каждом шаге &amp;lt;tex&amp;gt;d(i,c)&amp;lt;/tex&amp;gt;, для &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; от 0 до &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt;, по рекуррентной формуле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
d(i,c) =&lt;br /&gt;
\begin{cases}&lt;br /&gt;
 d(i - 1, c) &amp;amp; for\ c = 0, ..., w_i - 1; \\&lt;br /&gt;
 min(d(i - 1, c), d(i, c - w_i) + 1) &amp;amp; for\ c = w_i, ..., W; &lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После выполнения в &amp;lt;tex&amp;gt; d(N,W) &amp;lt;/tex&amp;gt; будет лежать максимальная стоимость предметов, помещающихся в рюкзак.&lt;br /&gt;
&lt;br /&gt;
Если не нужно восстанавливать ответ, то можно использовать одномерный массив &amp;lt;tex&amp;gt;d(c)&amp;lt;/tex&amp;gt; вместо двумерного и использовать формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  d(c) = min(d(c), d(c - w_i) + 1) \qquad  for\ c = w_i, ..., W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма &amp;lt;tex&amp;gt;O(NW)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Задача об упаковке==&lt;br /&gt;
'''Задача об упаковке''' (англ. ''Bin Packing Problem'') - имеются &amp;lt;tex&amp;gt; N &amp;lt;/tex&amp;gt; рюкзаков вместимости &amp;lt;tex&amp;gt; W &amp;lt;/tex&amp;gt; и столько же предметов с весами &amp;lt;tex&amp;gt;w_i&amp;lt;/tex&amp;gt;. Нужно распределить все предметы, задействовав минимальное количество рюкзаков.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' Нужно вывезти из шахты все куски руды, используя наименьшее число вагонеток.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Математически задачу можно представить так:&lt;br /&gt;
&lt;br /&gt;
*минимизировать количество рюкзаков: &amp;lt;tex&amp;gt;\sum_{i=1}^N y_i&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
*так чтобы выполнялось условие на совместность: &amp;lt;tex&amp;gt;\sum_{i=1}^N w_ix_{ij} \le Wy_j \qquad j \in {1, ..., N}&amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; x_{ij} = 1 &amp;lt;/tex&amp;gt; если &amp;lt;tex&amp;gt; j&amp;lt;/tex&amp;gt; предмет назначен  &amp;lt;tex&amp;gt;i &amp;lt;/tex&amp;gt; рюкзаку. Иначе &amp;lt;tex&amp;gt; x_{ij} = 0 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; y_i = 1 &amp;lt;/tex&amp;gt; если &amp;lt;tex&amp;gt; i&amp;lt;/tex&amp;gt; рюкзак используется. Иначе &amp;lt;tex&amp;gt; y_i = 0 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Применение динамического программирования нецелесообразно. Обычно применяют аппроксимационные алгоритмы, либо используют метод ветвей и границ.&lt;br /&gt;
&lt;br /&gt;
==Мультипликативный рюкзак==&lt;br /&gt;
'''Мультипликативный рюкзак''' (англ. ''Multiple Knapsack Problem'') - есть &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; предметов и &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; рюкзаков (&amp;lt;tex&amp;gt;M\le N&amp;lt;/tex&amp;gt;). У каждого рюкзака своя вместимость &amp;lt;tex&amp;gt;W_i&amp;lt;/tex&amp;gt;. Задача: выбрать &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; не пересекающихся множеств, назначить соответствие рюкзакам так, чтобы суммарная стоимость была максимальна, а вес предметов в каждом рюкзаке не превышал его вместимость.&lt;br /&gt;
&lt;br /&gt;
'''Пример:''' У транспортной компании есть парк машин разной грузоподъемности. Нужно перевезти товара на максимальную сумму с одного склада на другой единовременно.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
Максимизировать &amp;lt;tex&amp;gt;\sum_{i=1}^M \sum_{j=1}^{N} p_jx_{ij}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
так, чтобы &amp;lt;tex&amp;gt;\sum_{i=1}^N w_jx_{ij} \le W_i&amp;lt;/tex&amp;gt; выполнялось для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{j=1}^{M}x_{ij}=1&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; i= 1,2,...,N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; x_{ij} = 1 &amp;lt;/tex&amp;gt; если &amp;lt;tex&amp;gt; j&amp;lt;/tex&amp;gt; предмет назначен  &amp;lt;tex&amp;gt;i &amp;lt;/tex&amp;gt; рюкзаку. Иначе &amp;lt;tex&amp;gt; x_{ij} = 0 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Применение динамического программирования, для задач данного типа нецелесообразно. Используются вариации метода ветвей и границ.&lt;br /&gt;
&lt;br /&gt;
==Задача о назначении==&lt;br /&gt;
'''Задача о назначении''' (англ. ''Generalized Assignment Problem'') - Наиболее общая задача семейства. Отличается от мультипликативного рюкзака тем, что каждый предмет имеет различные характеристики в зависимости от рюкзака, куда его помещают. Есть &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; предметов и &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; рюкзаков (&amp;lt;tex&amp;gt;M\le N&amp;lt;/tex&amp;gt;). У каждого рюкзака своя вместимость &amp;lt;tex&amp;gt;W_i&amp;lt;/tex&amp;gt;, у &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt; предмета &amp;lt;tex&amp;gt; p_{ij} &amp;lt;/tex&amp;gt; стоимость и вес, при помещении его в &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; рюкзак, равны &amp;lt;tex&amp;gt; p_{ij} &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_{ij} &amp;lt;/tex&amp;gt;  соответственно.  Задача: выбрать &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; не пересекающихся множеств, назначить соответствие рюкзакам так, чтобы суммарная стоимость была максимальна, а вес предметов в каждом рюкзаке не превышал его вместимость.&lt;br /&gt;
Весьма важная задача, так как она моделирует оптимальное распределение различных задач между вычислительными блоками.&lt;br /&gt;
===Формулировка Задачи===&lt;br /&gt;
&lt;br /&gt;
Максимизировать стоимость выбранных предметов &amp;lt;tex&amp;gt;\sum_{i=1}^M\sum_{j=1}^N p_{ij} x_{ij}&amp;lt;/tex&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
при выполнении условия совместности &amp;lt;tex&amp;gt;\sum_{j=1}^N w_{ij} x_{ij} \le W_i \qquad i=1, \ldots, M&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; \sum_{i=1}^M x_{ij} \leq 1 \qquad j=1, \ldots, N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; x_{ij} \in \{0,1\} \qquad i=1, \ldots, N, \quad j=1, \ldots, N&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Варианты решения===&lt;br /&gt;
Применение динамического программирования нецелесообразно. Наиболее используем метод ветвей и границ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
*[http://informatics.mccme.ru/moodle/mod/book/view.php?id=815&amp;amp;chapterid=60 Дистанционная подготовка по информатике]&lt;br /&gt;
*[http://rosettacode.org/wiki/Knapsack_Problem Код для нескольких задач семейства на всевозможных языках]&lt;br /&gt;
*[http://www.diku.dk/users/pisinger/95-1.pdf David Pisinger Knapsack problems. — 1995]&lt;br /&gt;
*Silvano Martello, Paolo Toth. Knapsack Problems: Algorithms and Computer Implementations — 1990 г. — ISBN 0-471-92420-2&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>94.26.129.35</name></author>	</entry>

	</feed>