Мы знаем, что проблема ранца может быть решена в O (nW) сложности динамическим программированием. Но мы говорим, что это NP-полная проблема. Я чувствую, что здесь трудно понять.
(n - количество элементов. W - максимальный объем.)
Мы знаем, что проблема ранца может быть решена в O (nW) сложности динамическим программированием. Но мы говорим, что это NP-полная проблема. Я чувствую, что здесь трудно понять.
(n - количество элементов. W - максимальный объем.)
O(n*W)
выглядит как полиномиальное время, но это не так, это псевдополином.
Временная сложность измеряет время, которое алгоритм берет как функцию длины в битах своего ввода. Решение динамического программирования действительно линейно по значению W
, но экспоненциально по длине W
- и это важно!
Точнее говоря, временная сложность динамического решения задачи о ранце в основном определяется вложенным циклом:
// here goes other stuff we don't care about
for (i = 1 to n)
for (j = 0 to W)
// here goes other stuff
Таким образом, сложность времени явно O(n*W)
.
Что означает линейное увеличение размера входных данных алгоритма? Это означает использование прогрессивно более длинных массивов элементов (например, n
, n+1
, n+2
,...) и более длинных W
(поэтому, если длина W
равна x
битам, после одного шага мы используем x+1
бит, а затем x+2
бита,...). Но значение W
растет экспоненциально с x
, таким образом, алгоритм на самом деле не полиномиальный, он экспоненциальный (но он выглядит как полиномиальный, отсюда и название: "псевдополиномиальный").
В задаче о ранце 0/1 нам нужно 2 входа (1 массив и 1 целое число), чтобы решить эту проблему:
Предположим, что n = 10 и W = 8:
поэтому сложность по времени T (n) = O (nW) = O (10 * 8) = O (80)
Если вы удвоите размер n:
n = [n1, n2, n3,..., n10 ] → n = [n1, n2, n3,..., n20 ]
поэтому сложность по времени T (n) = O (nW) = O (20 * 8) = O (160)
но если вы удвоите размер W, это не означает, что W = 16, но длина будет вдвое больше:
W = 1000 → W = 10000000 в двоичном выражении (8-битная длина)
поэтому T (n) = O (nW) = O (10 * 128) = O (1280)
необходимое время увеличивается в геометрической прогрессии, так что это проблема NPC.
Все зависит от параметров, которые вы помещаете внутри O(...)
.
Если целевой вес ограничен числом W
, тогда проблема имеет сложность O(n*W)
, как вы упомянули.
Но если веса слишком велики, и вам нужен алгоритм со сложностью, не зависящей от W
, тогда проблема NP-полная. (O(2^n*n)
в самой наивной реализации).
Это связано с тем, что задача о ранце имеет псевдополиномиальное решение и поэтому называется слабо NP-полной (а не сильно NP-полной).
Размер ввода - это log(W)
бит для веса (и O(n)
для массивов "value" и "weight").
Таким образом, входной размер веса равен j = log(W)
(а не просто W
). Итак, W = 2ʲ
(в качестве бинарного W = 2ʲ
).
Конечная сложность O(n * W)
Это
O(n * W)
может быть переписано какO(n * 2ʲ)
, что экспоненциально по отношению к размеру ввода.
Таким образом, это решение не является полиномиальным.
Вы можете прочитать это краткое объяснение: NP-Полнота рюкзака.
Чтобы понять NP-полноту, вам нужно немного изучить теорию сложности. Однако, в основном, он NP-завершен, потому что эффективный алгоритм для задачи о ранце также будет эффективным алгоритмом для SAT, TSP и всего остального.