<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>https://discopal.ispras.ru/index.php?action=history&amp;feed=atom&amp;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%3APTAS</id>
		<title>Задача о рюкзаке:PTAS - История изменений</title>
		<link rel="self" type="application/atom+xml" href="https://discopal.ispras.ru/index.php?action=history&amp;feed=atom&amp;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%3APTAS"/>
		<link rel="alternate" type="text/html" href="https://discopal.ispras.ru/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:PTAS&amp;action=history"/>
		<updated>2026-05-13T12:47:11Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.26.4</generator>

	<entry>
		<id>https://discopal.ispras.ru/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:PTAS&amp;diff=1117&amp;oldid=prev</id>
		<title>WikiSysop: 1 версия</title>
		<link rel="alternate" type="text/html" href="https://discopal.ispras.ru/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:PTAS&amp;diff=1117&amp;oldid=prev"/>
				<updated>2008-10-23T16:48:04Z</updated>
		
		<summary type="html">&lt;p&gt;1 версия&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Задача о рюкзаке:динамическое программирование|Алгоритмы динамического программирования для задачи]] о рюкзаке дают точное решение за время ''O(nf&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;)'' или ''O(nB)''. Если величины ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'' и ''B'' не ограничена сверху никаким полиномом (то есть имеются большие коэффициенты), то эти псевдополиномиальные алгоритмы не является полиномиальными.&lt;br /&gt;
&lt;br /&gt;
Однако, существует общий метод (который условно можно назвать «масштабированием»), позволяющий перейти к задаче с небольшими коэффициентами в целевой функции, оптимум которой не сильно&lt;br /&gt;
отличается от оптимума исходной задачи.&lt;br /&gt;
&lt;br /&gt;
Если мы отмасштабируем коэффициенты &amp;lt;m&amp;gt;c_1, \ldots, c_n&amp;lt;/m&amp;gt;, &lt;br /&gt;
поделив нацело их на некоторый параметр ''scale'', &lt;br /&gt;
решим «отмасштабированную» задачу, и затем снова умножим коэффициенты на параметр ''scale'', то&lt;br /&gt;
очевидно, что мы получим допустимое решение исходной задачи и &lt;br /&gt;
абсолютная погрешность стоимости «округленного и восстановленного» набора не превосходит величины&lt;br /&gt;
&amp;lt;m&amp;gt;n \cdot scale&amp;lt;/m&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Если потребовать, чтобы эта величина не превосходила&lt;br /&gt;
&amp;lt;m&amp;gt;\frac{\varepsilon}{1+\varepsilon}f^*&amp;lt;/m&amp;gt;, то получим,&lt;br /&gt;
что каждое допустимое решение исходной задачи&lt;br /&gt;
отличается от решения «отмасштабированной» задачи не более, чем на эту же величину.&lt;br /&gt;
&lt;br /&gt;
Обозначая оптимум «отмасштабированной» задачи через &amp;lt;m&amp;gt;\tilde f&amp;lt;/m&amp;gt;, получаем, что&lt;br /&gt;
&amp;lt;m&amp;gt;&lt;br /&gt;
 \tilde f \geq f^* - \frac{\varepsilon}{1+\varepsilon}f^* = \frac{f^*}{(1+\varepsilon)},&lt;br /&gt;
&amp;lt;/m&amp;gt;&lt;br /&gt;
т. е. оптимум «отмасштабированной» задачи отличается от оптимума исходной задачи не более, чем в&lt;br /&gt;
&amp;lt;m&amp;gt;1+\varepsilon&amp;lt;/m&amp;gt; раз.&lt;br /&gt;
 &lt;br /&gt;
При этом величина значение оптимального решения для «отмасштабированной» задачи уменьшается не менее, чем в ''scale'' раз по сравнению с исходной.&lt;br /&gt;
И таким образом, для отмасштабированной задачи, версия [[Задача о рюкзаке:динамическое программирование|алгоритма, ориентированная на отбор «самых легких решений»]] будет работать существенно меньшее время.&lt;br /&gt;
&lt;br /&gt;
Однако проблема состоит в том, что в момент масштабирования&lt;br /&gt;
мы не знаем величины оптимума ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'', и не можем выбрать&lt;br /&gt;
коэффициент ''scale'', который, чтобы решение было &amp;lt;m&amp;gt;1+\varepsilon&amp;lt;/m&amp;gt;-оптимальным, не должен превышать &amp;lt;m&amp;gt;\frac{\varepsilon f^*}{n(1+\varepsilon)}&amp;lt;/m&amp;gt;, с одной стороны,&lt;br /&gt;
с другой — желательно максимально приблизить его к этой оценке, чтобы уменьшить коэффициенты в задаче.&lt;br /&gt;
&lt;br /&gt;
Поэтому, важное наблюдение состоит в том, что вместо ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'' можно&lt;br /&gt;
рассматривать нижнюю оценку ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'', обозначим ее ''f&amp;lt;sub&amp;gt;lb&amp;lt;/sub&amp;gt;'',&lt;br /&gt;
и выбирать параметр масштабирования &amp;lt;m&amp;gt;scale=\frac{\varepsilon f_{lb}}{n(1+\varepsilon)}&amp;lt;/m&amp;gt;&lt;br /&gt;
тогда все вышеизложенные соображения о точности «отмасштабированного» решения сохранят силу.&lt;br /&gt;
&lt;br /&gt;
Таким образом, стоит задача выбора нижней оценки ''f&amp;lt;sub&amp;gt;lb&amp;lt;/sub&amp;gt;'', которую можно найти быстро с одной стороны, и желательно чтобы она была как можно ближе к ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'', т. к. это даст возможность увеличить коэффициент ''scale'', и тем самым, сильнее уменьшить коэффициенты &amp;lt;m&amp;gt;c_1,\ldots,c_n&amp;lt;/m&amp;gt; и время выполнения алгоритма.&lt;br /&gt;
Таким образом, общая схема алгоритма,&lt;br /&gt;
представлена как процедура «knapsack_ptas_generic»,&lt;br /&gt;
которой на вход, кроме обычных параметров рюкзака, передают функцию &lt;br /&gt;
«f_lower_bound», используемую для получения нижней оценки стоимости решения.&lt;br /&gt;
&lt;br /&gt;
Осталось найти такую функцию. Например, можно рассмотреть тривиальную аппроксимацию&lt;br /&gt;
&amp;lt;m&amp;gt;&lt;br /&gt;
    n c_{\max} \geq f^* \geq f_{lb} \equiv c_{\max},&lt;br /&gt;
&amp;lt;/m&amp;gt;, где &amp;lt;m&amp;gt;c_{\max}=\max_{i} c_i&amp;lt;/m&amp;gt;; и получим функцию «knapsack_ptas_trivial».&lt;br /&gt;
&lt;br /&gt;
Какова сложность этого алгоритма? Она, есть величина &amp;lt;m&amp;gt;O(n \tilde f)&amp;lt;/m&amp;gt;. &lt;br /&gt;
Учитывая, что &amp;lt;m&amp;gt;f^* \leq nc_{max}&amp;lt;/m&amp;gt;, а &amp;lt;m&amp;gt;\tilde f \leq \frac{nc_{max}}{scale}&amp;lt;/m&amp;gt;, получаем оценку сложности алгоритма «knapsack_ptas_trivial»:&lt;br /&gt;
&amp;lt;m&amp;gt;&lt;br /&gt;
 O(n \tilde f)=O\left(n^2\frac{c_{max}}{scale}\right)&lt;br /&gt;
 =O\left(\frac{n^3(1+\varepsilon)}{\varepsilon}\right)&lt;br /&gt;
 =O\left(\frac{n^3}{\varepsilon}\right).&lt;br /&gt;
&amp;lt;/m&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно ли улучшить эту оценку? Ответ на этот вопрос положителен.&lt;br /&gt;
&lt;br /&gt;
Для этого рассмотрим менее наивную аппроксимацию&lt;br /&gt;
величины ''f&amp;lt;sup&amp;gt;*&amp;lt;/sup&amp;gt;'', используя [[задача о рюкзаке:жадный алгоритм]], дающий точность не хуже чем в два раза.&lt;br /&gt;
&lt;br /&gt;
Используя эту оценку, получаем функцию «knapsack_ptas_nontrivial» &lt;br /&gt;
Аналогично получаем оценку сложности для этого алгоритма:&lt;br /&gt;
&amp;lt;m&amp;gt;&lt;br /&gt;
 O(n \tilde f)&lt;br /&gt;
=O\left(n \frac{f_G}{scale}\right)&lt;br /&gt;
=O\left(\frac{n^2(1+\varepsilon)}{\varepsilon}\right)&lt;br /&gt;
=O\left(\frac{n^2}{\varepsilon}\right).&lt;br /&gt;
&amp;lt;/m&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code-python&amp;gt;&lt;br /&gt;
# Динамическое программирования для рюкзака,&lt;br /&gt;
# с отбором «наиболее легких» частичных решений.&lt;br /&gt;
def knapsack_dylp_lightest(A,B,C):&lt;br /&gt;
    T={0:0} #Хэш: самый малый вес для стоимости - {стоимость:минимальный вес}&lt;br /&gt;
    Solution={0:[]}&lt;br /&gt;
    #Цикл по всем предметам $\frac{c_i}{a_i}$&lt;br /&gt;
    for i in range(0,len(A)):&lt;br /&gt;
        T_old=dict(T)  #Копируем $T_{k-1}$ в $T_{old}$&lt;br /&gt;
        for x in T_old:&lt;br /&gt;
            if (T_old[x]+A[i])&amp;lt;=B:&lt;br /&gt;
                if (not T.has_key(x+C[i])) or (T_old[x]+A[i]&amp;lt;T_old[x+C[i]]):&lt;br /&gt;
                    T[x+C[i]]=T_old[x]+A[i]&lt;br /&gt;
                    Solution[x+C[i]]=Solution[x]+[i]&lt;br /&gt;
&lt;br /&gt;
    ResultCost = max(T.keys())&lt;br /&gt;
    Result = Solution[ResultCost]&lt;br /&gt;
    return Result&lt;br /&gt;
&lt;br /&gt;
# PTAS для рюкзака. Общая схема.&lt;br /&gt;
def knapsack_ptas_generic(A,B,C,epsilon,f_lower_bound):&lt;br /&gt;
    print &amp;quot;A=&amp;quot;,A&lt;br /&gt;
    print &amp;quot;B=&amp;quot;,B&lt;br /&gt;
    print &amp;quot;C=&amp;quot;,C&lt;br /&gt;
    print &amp;quot;epsilon=&amp;quot;,epsilon&lt;br /&gt;
&lt;br /&gt;
    #Вычисляем нижнюю оценку стоимости и параметр округления $scale$&lt;br /&gt;
    F_lb=f_lower_bound(A,B,C)&lt;br /&gt;
    print &amp;quot;F_lb=&amp;quot;,F_lb&lt;br /&gt;
&lt;br /&gt;
    scale=floor(epsilon*F_lb/len(C)/(1+epsilon))&lt;br /&gt;
    print &amp;quot;scale=&amp;quot;,scale&lt;br /&gt;
&lt;br /&gt;
    #Округляем коэффициенты &lt;br /&gt;
    C_=[]&lt;br /&gt;
    for i in range(0,len(A)):&lt;br /&gt;
        C_.insert(i, int(floor(C[i] / scale)))&lt;br /&gt;
    print &amp;quot;C_=&amp;quot;,C_&lt;br /&gt;
&lt;br /&gt;
    ApproxResult=knapsack_dylp_lightest(A,B,C_)&lt;br /&gt;
&lt;br /&gt;
    ApproxCost=0&lt;br /&gt;
    for i in ApproxResult:&lt;br /&gt;
            ApproxCost=ApproxCost+C[i]&lt;br /&gt;
            &lt;br /&gt;
    return (ApproxResult,ApproxCost)        &lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
def knapsack_lower_bound_trivial(A,B,C):&lt;br /&gt;
    #Простая оценка нижней границы стоимости решения.&lt;br /&gt;
    return max(C) &lt;br /&gt;
&lt;br /&gt;
def knapsack_lower_bound_greedy(A,B,C):&lt;br /&gt;
    #Оценка нижней границы через жадный алгоритм.&lt;br /&gt;
    return knapsack_greedy(A,B,C) &lt;br /&gt;
&lt;br /&gt;
# PTAS для рюкзака, сложности $O(\frac{n^3}{\varepsilon})$&lt;br /&gt;
def knapsack_ptas_trivial(A,B,C,epsilon):&lt;br /&gt;
    return knapsack_ptas_generic(A,B,C,epsilon,knapsack_lower_bound_trivial)&lt;br /&gt;
&lt;br /&gt;
# PTAS для рюкзака, сложности $O(\frac{n^2}{\varepsilon})$&lt;br /&gt;
def knapsack_ptas_nontrivial(A,B,C,epsilon):&lt;br /&gt;
    return knapsack_ptas_generic(A,B,C,epsilon,knapsack_lower_bound_greedy)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code-python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 knapsack_ptas_trivial:&lt;br /&gt;
 A= [16, 900, 440, 250, 667, 43, 333, 857, 474]&lt;br /&gt;
 B= 1000&lt;br /&gt;
 C= [134, 1354, 567, 789, 987, 56, 345, 4567, 5555]&lt;br /&gt;
 epsilon= 0.1&lt;br /&gt;
 F_lb= 5555&lt;br /&gt;
 scale= 56.0&lt;br /&gt;
 C_= [2, 24, 10, 14, 17, 1, 6, 81, 99]&lt;br /&gt;
 Cost= 6534&lt;br /&gt;
&lt;br /&gt;
 knapsack_ptas_nontrivial:&lt;br /&gt;
 A= [16, 900, 440, 250, 667, 43, 333, 857, 474]&lt;br /&gt;
 B= 1000&lt;br /&gt;
 C= [134, 1354, 567, 789, 987, 56, 345, 4567, 5555]&lt;br /&gt;
 epsilon= 0.1&lt;br /&gt;
 F_lb= 6534&lt;br /&gt;
 scale= 66.0&lt;br /&gt;
 C_= [2, 20, 8, 11, 14, 0, 5, 69, 84]&lt;br /&gt;
 Cost= 6478&lt;br /&gt;
&lt;br /&gt;
 knapsack_ptas_nontrivial:&lt;br /&gt;
 A= [16, 900, 440, 250, 667, 43, 333, 857, 474]&lt;br /&gt;
 B= 1000&lt;br /&gt;
 C= [134, 1354, 567, 789, 987, 56, 345, 4567, 5555]&lt;br /&gt;
 epsilon= 0.08&lt;br /&gt;
 F_lb= 6534&lt;br /&gt;
 scale= 53.0&lt;br /&gt;
 C_= [2, 25, 10, 14, 18, 1, 6, 86, 104]&lt;br /&gt;
 Cost= 6534&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Алгоритмы]]&lt;br /&gt;
{{replicate-from-custiswiki-to-lib}}&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>	</entry>

	</feed>