Мы знаем, что проблема ранца может быть решена в 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 и всего остального.