<?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=95.72.63.243&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=95.72.63.243&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/95.72.63.243"/>
		<updated>2026-04-24T19:39:48Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE_%D0%BF%D1%80%D0%BE%D1%84%D0%B8%D0%BB%D1%8E&amp;diff=80787</id>
		<title>Динамическое программирование по профилю</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE_%D0%BF%D1%80%D0%BE%D1%84%D0%B8%D0%BB%D1%8E&amp;diff=80787"/>
				<updated>2021-04-12T06:28:37Z</updated>
		
		<summary type="html">&lt;p&gt;95.72.63.243: /* нам понадобиться O(a^nm) времени -&amp;gt; нам понадобится O(a^nm) времени */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition='''Динамическое программирование по профилю''' (англ. ''dynamic programming with profile'') {{---}} способ оптимизации перебора количества вариантов с помощью [[Динамическое программирование|динамического программирования]], когда одно из измерений небольшое.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Профиль''' (англ. ''profile'') {{---}} один из столбцов (строк), удовлетворяющий условию задачи. Обычно используется в качестве состояния динамики.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Общие принципы ==&lt;br /&gt;
Обычно дана таблица и надо посчитать количество замощений этой таблицы некоторыми фигурами (замощение шахматной доски доминошками). Можно перебрать все варианты и выбрать из них удовлетворяющие условию. Но можно воспользоваться методом динамического программирования по профилю и сократить время по одной размерности до линейной. Затем пусть у нас есть правило по которому надо заполнить и для него нам надо &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; предыдущих линий. Тогда можно перебрать все замощения  длиной &amp;lt;tex&amp;gt;k\times n&amp;lt;/tex&amp;gt;. В итоге нужно заполнить данную таблицу этими замощениями. Получается, что если перебирать все варианты нам понадобится &amp;lt;tex&amp;gt;O(a^{nm})&amp;lt;/tex&amp;gt; времени, а если перебирать только состояния и переходить по ним нам потребуется &amp;lt;tex&amp;gt;O(a^{kn}m)&amp;lt;/tex&amp;gt; времени (где &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} количество способов замощения одной клетки).&lt;br /&gt;
&lt;br /&gt;
== '''Задача о замощении домино''' ==&lt;br /&gt;
==='''Условие'''===&lt;br /&gt;
Найти количество способов замостить таблицу &amp;lt;tex&amp;gt;n\times m&amp;lt;/tex&amp;gt; с помощью доминошек размерами  &amp;lt;tex&amp;gt;1\times 2,2\times 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==='''Решение'''===&lt;br /&gt;
&lt;br /&gt;
[[Файл:Домино.png|270px|thumb|right|Переходы (1-правильный переход, 2,3-неправильные)]]&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;1&amp;lt;/tex&amp;gt; будет означать, что домино лежит горизонтально и заканчивается на этом столбце, иначе &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;. Таких профилей будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;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;j&amp;lt;/tex&amp;gt; можно перейти если выполняются условия:&lt;br /&gt;
&lt;br /&gt;
* Можно положить горизонтальные домино. То есть там где в &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; профиле стоит &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; профиле должен стоять &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Можно доложить в оставшиеся клетки вертикальные домино. То есть оставшиеся &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; профиле должны образовывать четные подстроки.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d[i][j] = 1&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;-ый, иначе &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть так же &amp;lt;tex&amp;gt;a[k][i]&amp;lt;/tex&amp;gt; {{---}} количество способов замощения первых &amp;lt;tex&amp;gt;k-1&amp;lt;/tex&amp;gt; столбцов и заканчивавшийся на &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом профиле.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;a[k][i]=\displaystyle \sum_{j=0}^{2^n -1} a[k-1][j]\cdot d[j][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответом будет &amp;lt;tex&amp;gt; \sum a[m][i]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; {{---}} профиль, который может быть последним (т.е. все группы из &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; имеют четные размеры).&lt;br /&gt;
&lt;br /&gt;
==='''Реализация'''===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// n, m {{---}} размер таблицы &amp;lt;/font&amp;gt; &lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;\mathtt{j} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' можно перейти из &amp;lt;tex&amp;gt;\mathtt{i}&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;\mathtt{j}&amp;lt;/tex&amp;gt; профиль &lt;br /&gt;
            &amp;lt;tex&amp;gt;\mathtt{d}[\mathtt{i}][\mathtt{j}] = \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 	'''else''' &lt;br /&gt;
 	    &amp;lt;tex&amp;gt;\mathtt{d}[\mathtt{i}][\mathtt{j}] = \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{a}[\mathtt{0}][\mathtt{0}] = \mathtt{1}&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt;// Так как мы можем начать только с профиля где все клетки 0 &amp;lt;/font&amp;gt; &lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;k = \mathtt{1}..\mathtt{m} - \mathtt{1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;\mathtt{j} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 	    &amp;lt;tex&amp;gt;\mathtt{a}[\mathtt{k}][\mathtt{i}] = \mathtt{a}[\mathtt{k}][\mathtt{i}] + \mathtt{a}[\mathtt{k} - \mathtt{1}][\mathtt{j}]  \cdot  \mathtt{d}[\mathtt{j}][\mathtt{i}]&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{ans} = \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} \lt \lt \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' можно закончить &amp;lt;tex&amp;gt;\mathtt{i}&amp;lt;/tex&amp;gt; профилем&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{ans} = \mathtt{ans} + \mathtt{a}[\mathtt{m} - \mathtt{1}][\mathtt{i}]&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''return''' &amp;lt;tex&amp;gt;\mathtt{ans}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''' Оценка сложности: '''&lt;br /&gt;
подсчет &amp;lt;tex&amp;gt;d - 2^{2n}&amp;lt;/tex&amp;gt; , и подсчет &amp;lt;tex&amp;gt;a - 2^{2n}m&amp;lt;/tex&amp;gt; в итоге &amp;lt;tex&amp;gt;O(2^{2n}m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''' Оценка памяти: '''&lt;br /&gt;
&amp;lt;tex&amp;gt;O(2^{2n} + 2^{2n}m)&amp;lt;/tex&amp;gt;, так же можно заметить что в массиве &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; состояния нам нужно только &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; состояние, при такой реализации нужно будет &amp;lt;tex&amp;gt;O(2^{2n})&amp;lt;/tex&amp;gt;. Еще можно не считать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, а просто каждый раз перепроверять можем ли мы перейти в это состояние в итоге потребуется &amp;lt;tex&amp;gt;O(2^{n + 1})&amp;lt;/tex&amp;gt; памяти, но нам потребуется больше времени &amp;lt;tex&amp;gt;2^{2n}mf(i,j)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;f(i,j)&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; равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и тогда время получается &amp;lt;tex&amp;gt;O(2^{2n}mn)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== '''Задача о симпатичных узорах''' ==&lt;br /&gt;
==='''Условие'''===&lt;br /&gt;
Дана таблица &amp;lt;tex&amp;gt;n\times m&amp;lt;/tex&amp;gt;, каждая клетка которой может быть окрашена в один из двух&lt;br /&gt;
цветов: белый или черный. Симпатичным узором называется такая раскраска, при&lt;br /&gt;
которой не существует квадрата &amp;lt;tex&amp;gt;2\times 2&amp;lt;/tex&amp;gt;, в котором все клетки одного цвета. Требуется найти количество симпатичных узоров для соответствующей таблицы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Симпатичне узоры.png|240px|thumb|right|]]&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;1&amp;lt;/tex&amp;gt; будет означать что клетка закрашена в черный цвет, и &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;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;-ый можно перейти если выполнено условие:&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;2\times 2&amp;lt;/tex&amp;gt; одного цвета&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d[i][j] = 1&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;-ый, иначе &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть так же &amp;lt;tex&amp;gt;a[k][i]&amp;lt;/tex&amp;gt; {{---}} количество способов раскрашивания первые &amp;lt;tex&amp;gt;k-1&amp;lt;/tex&amp;gt; столбцов и заканчивавшийся на &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом профиле.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;a[k][i]=\displaystyle \sum_{j=0}^{2^n -1} a[k-1][j]\cdot d[j][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответом будет &amp;lt;tex&amp;gt; \displaystyle \sum_{i=0}^{2^n -1} a[m][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Реализация'''===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// n, m {{---}} размер таблицы &amp;lt;/font&amp;gt;  &lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;\mathtt{j} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' можно перейти из &amp;lt;tex&amp;gt;\mathtt{i}&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;\mathtt{j}&amp;lt;/tex&amp;gt; профиль &lt;br /&gt;
             &amp;lt;tex&amp;gt;\mathtt{d}[\mathtt{i}][\mathtt{j}]\ =\ \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 	'''else'''&lt;br /&gt;
 	    &amp;lt;tex&amp;gt;\mathtt{d}[\mathtt{i}][\mathtt{j}]\ =\ \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{a}[0][\mathtt{i}]\ = \mathtt{1}&amp;lt;/tex&amp;gt; &amp;lt;font color=green &amp;gt;// Так как мы можем начать c любого профиля&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;\mathtt{k} = \mathtt{1}.. \mathtt{m} - \mathtt{1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for'''  &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;\mathtt{j} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 	     &amp;lt;tex&amp;gt;\mathtt{a}[\mathtt{k}][\mathtt{i}] = \mathtt{a}[\mathtt{k}][\mathtt{i}] + \mathtt{a}[\mathtt{k} - 1][\mathtt{j}] \cdot \mathtt{d}[\mathtt{j}][\mathtt{i}]&amp;lt;/tex&amp;gt;  &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{ans} = \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;\mathtt{i} = \mathtt{0}..(\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n}) - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{ans} = \mathtt{ans} + \mathtt{a}[\mathtt{m} - \mathtt{1}][\mathtt{i}]&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt;// Так как мы можем закончить любым профилем &amp;lt;/font&amp;gt;&lt;br /&gt;
 '''return''' &amp;lt;tex&amp;gt;\mathtt{ans}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''' Оценка сложности: '''&lt;br /&gt;
подсчет &amp;lt;tex&amp;gt;d - 2^{2n}&amp;lt;/tex&amp;gt; , и подсчет &amp;lt;tex&amp;gt;a - 2^{2n}m&amp;lt;/tex&amp;gt; в итоге &amp;lt;tex&amp;gt;O(2^{2n}m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
''' Оценка памяти: '''&lt;br /&gt;
&amp;lt;tex&amp;gt;O(2^{2n}+2^{2n}m)&amp;lt;/tex&amp;gt;, так же можно заметить что в массиве &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; состояния нам нужно только &amp;lt;tex&amp;gt;k-1&amp;lt;/tex&amp;gt; состояние, при такой реализации нужно будет &amp;lt;tex&amp;gt;O(2^{2n})&amp;lt;/tex&amp;gt;. Еще можно не считать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, а просто каждый раз перепроверять можем ли мы перейти в это состояние в итоге потребуется &amp;lt;tex&amp;gt;O(2^{n + 1})&amp;lt;/tex&amp;gt; памяти, но нам потребуется больше времени &amp;lt;tex&amp;gt;2^{2n}mf(i,j)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;f(i,j)&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; равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и тогда время получается &amp;lt;tex&amp;gt;O(2^{2n}mn)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Динамика по изломанному профилю ==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Изломанный профиль''' (англ. ''broken profile'') {{---}} обобщение прямого профиля на случай, когда обработанным является не целое число столбцов, а некоторое количество столбцов и несколько первых клеток следующего столбца.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Это очень сильная оптимизация динамики по профилю. Идея в том, чтобы добиться как можно меньшего числа переходов (от одного профиля к другому).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
Еще раз используем в качестве примера задачу о замощении. Базовая линия теперь будет ломаной: при прохождении через &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ю вертикаль сверху вниз, она переходит на предыдущую вертикаль и спускается до низу. Теперь профиль — это не только маска, но ещё и место излома.&lt;br /&gt;
[[Файл:img34.gif|300px|thumb|right|]]&lt;br /&gt;
Профилем будет пара &amp;lt;tex&amp;gt;(p, i)&amp;lt;/tex&amp;gt;, в &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; будет информация о &amp;lt;tex&amp;gt;n + 1&amp;lt;/tex&amp;gt; маленьком квадратике слева от базовой линии, имеющем с ней общие точки; &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; обозначает номер горизонтали, на которой произошел излом. Квадратики профиля будут нумероваться сверху вниз, так что угловой будет иметь номер &amp;lt;tex&amp;gt;i + 1&amp;lt;/tex&amp;gt;. Горизонтали будем нумеровать с нуля, так что &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; пробегает значения от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;n - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;d[pr_1][pr_2] = 1&amp;lt;/tex&amp;gt; если из профиля &amp;lt;tex&amp;gt;pr_1&amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt;(p_1, i_1)&amp;lt;/tex&amp;gt; можно перейти в &amp;lt;tex&amp;gt;pr_2 = (p_2, i_2)&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Eсли &amp;lt;tex&amp;gt;i &amp;lt; n - 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;i_1 + 1 = i_2&amp;lt;/tex&amp;gt;, иначе &amp;lt;tex&amp;gt;i_2 = 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
* Mожно так положить доминошку, накрывающую квадратик с номером &amp;lt;tex&amp;gt;i + 1&amp;lt;/tex&amp;gt;, что после этого в &amp;lt;tex&amp;gt;p_2&amp;lt;/tex&amp;gt; будет храниться в точности информация о соответствующих квадратиках.&lt;br /&gt;
Проще говоря, доминошку можно класть только двумя способами {{---}} как показано на рисунках (на квадратик с номером &amp;lt;tex&amp;gt;i + 1&amp;lt;/tex&amp;gt; можно положить не более одной вертикальной и горизонтальной доминошки). То, что потом получается после сдвига вниз излома, и будет новым профилем. Заметим, что если  клетка &amp;lt;tex&amp;gt;i + 1&amp;lt;/tex&amp;gt; занята, то доминошку уже не надо класть, и &amp;lt;tex&amp;gt;(p, i)&amp;lt;/tex&amp;gt; логично отождествить с &amp;lt;tex&amp;gt;(p, i + 1)&amp;lt;/tex&amp;gt;. Условно пишется  {{---}} &amp;quot;&amp;lt;tex&amp;gt;i + 1&amp;lt;/tex&amp;gt;&amp;quot;, однако, нужно всегда иметь в виду возможность &amp;lt;tex&amp;gt;i = n - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Легко заметить, что количество профилей увеличилось в &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; раз (добавилось число от &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и еще один бит). Но зато количество переходов резко сократилось с &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;//Для профиля (p, i) выводятся все переходы из него (нумерация горизонталей начинается с нуля и i = 0..n - 1)&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// Функция bit(x,i), возвращающая единицу или ноль или i-й бит в двоичной записи числа x&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''print_all_links'''(&amp;lt;tex&amp;gt;\mathtt{p}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathtt{i}&amp;lt;/tex&amp;gt;):&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{bit}(\mathtt{p, \mathtt{i} + \mathtt{1}}) == \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;\mathtt{i} == \mathtt{n} - \mathtt{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''println'''&amp;lt;tex&amp;gt;((\mathtt{p} - (\mathtt{2} &amp;lt;&amp;lt; \ \mathtt{i})) &amp;lt;&amp;lt; \ \mathtt{1}&amp;lt;/tex&amp;gt;, &amp;quot; &amp;quot;, &amp;lt;tex&amp;gt;\mathtt{0})&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''else'''&lt;br /&gt;
             '''println'''&amp;lt;tex&amp;gt;(\mathtt{p} - (\mathtt{2} &amp;lt;&amp;lt; \ \mathtt{i})&amp;lt;/tex&amp;gt;, &amp;quot; &amp;quot;, &amp;lt;tex&amp;gt;\mathtt{i} + \mathtt{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else''' &lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;\mathtt{bit}(\mathtt{p}, \mathtt{i}) == \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''if''' &amp;lt;tex&amp;gt;\mathtt{i} == \mathtt{n} - \mathtt{1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
                '''println'''&amp;lt;tex&amp;gt;((\mathtt{p} &amp;lt;&amp;lt; \ \mathtt{1})&amp;lt;/tex&amp;gt;, &amp;quot; &amp;quot;, &amp;lt;tex&amp;gt;\mathtt{0})&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''else'''   &lt;br /&gt;
                '''println'''&amp;lt;tex&amp;gt;(\mathtt{p} + (\mathtt{1} &amp;lt;&amp;lt; \ \mathtt{n})&amp;lt;/tex&amp;gt;, &amp;quot; &amp;quot;, &amp;lt;tex&amp;gt;(\mathtt{i} + \mathtt{1}) % \mathtt{n})&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{i} &amp;lt; \mathtt{n} - \mathtt{1}&amp;lt;/tex&amp;gt; &amp;amp;&amp;amp; &amp;lt;tex&amp;gt;\mathtt{bit}(\mathtt{p, \mathtt{i} + \mathtt{2}}) == \mathtt{0}&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''println'''&amp;lt;tex&amp;gt;(\mathtt{p} + (\mathtt{4} &amp;lt;&amp;lt; \ \mathtt{i})&amp;lt;/tex&amp;gt;, &amp;quot; &amp;quot;, &amp;lt;tex&amp;gt;\mathtt{i} + \mathtt{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
[[Файл:ok.jpg|640px|thumb|left|Возможные переходы]]&lt;br /&gt;
&lt;br /&gt;
При такой реализации существует немало профилей только с одним переходом (например, у которых &amp;lt;tex&amp;gt;(i + 1)&amp;lt;/tex&amp;gt;-й бит равен единице).&lt;br /&gt;
Отождествим все профили с один переходом с теми, кто их них получается. Это будет выглядеть так: пусть &amp;lt;tex&amp;gt;pr_2&amp;lt;/tex&amp;gt; (и только он) получается из &amp;lt;tex&amp;gt;pr_1&amp;lt;/tex&amp;gt;, который, в свою очередь, получается из &amp;lt;tex&amp;gt;pr_0&amp;lt;/tex&amp;gt;. Тогда имеются такие соотношения: &amp;lt;tex&amp;gt;d[pr_0, pr_1] = 1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;d[pr_1, pr_2] = 1&amp;lt;/tex&amp;gt;. Отождествить &amp;lt;tex&amp;gt;pr_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;pr_2&amp;lt;/tex&amp;gt; {{---}} это, по сути, заменить эти два соотношение на одно, то есть теперь &amp;lt;tex&amp;gt;d[pr_0, pr_1] = 0&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[pr_1, pr_2] = 0&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;d[pr_0, pr_2] = 1&amp;lt;/tex&amp;gt;, и так далее.&lt;br /&gt;
&lt;br /&gt;
Таким образом, возможно сокращение профилей не менее чем вдвое. Хотя можно совершить дальнейшие оптимизации.&lt;br /&gt;
 &lt;br /&gt;
В итоге асимптотика составляет &amp;lt;tex&amp;gt;O(2^nnm)&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/file.php/9/dyn_prof.pdf Динамическое программирование по профилю]&lt;br /&gt;
*[http://informatics.mccme.ru/mod/book/view.php?id=290&amp;amp;chapterid=78 Динамическое программирование по изломанному профилю]&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>95.72.63.243</name></author>	</entry>

	</feed>