最簡單的NP Hard問題

2021-09-11 09:39:41 字數 3569 閱讀 9936

本文介紹了最簡單的np-hard問題——數字分割槽問題,以及該問題的乙個偽多項式解法和兩個近似解法。

討論這樣乙個問題:給定乙個正整數的多重集合 ,能否將劃分為兩個子集和,使得中元素的和與中元素的和相等?在數論和電腦科學中,該問題被稱為是數字分割槽問題,儘管np完全,但是卻存在動態規劃的解法能夠在偽多項式時間內求解,並且在許多情況下,存在最佳或者是近似的解決方法。因此,這個問題也被稱為"最簡單的np-hard問題"。

比如給定多重集合存在子集和,這兩個子集劃分了。這個解並不是唯一的。和是另外一組解。

並不是所有的多重集合都能找到這個問題的解,比如。

在多重集合元素的個數和多重集合元素的和值不是很大時,可以採用動態規劃來解決。

假設問題的輸入是具有個正整數的多重集合

設為中元素的和值。那麼演算法就是找出乙個的子集,其和為 。如果這樣的子集存在,那麼:

用來表示在中是否存在子集使得子集元素和為,如果存在,為;如果不存在,為。

那麼上面的問題就變成了判斷是否為。為了幫助解決這個問題,我們引入下面的命題:

當且僅當為或者為時,為。

下面來證明這個命題

證明:當為時,使得成立,,故為;

當為時,使得成立,則必有使得成立,,故為;

當為且為時,使得成立且使得成立,此時明顯使得成立(反證法可證)。

綜上,當且僅當

使用python來簡單實現上面的演算法:

#!/usr/bin/env python

import numpy as np

def find_partition(s):

n = len(s)

k = sum(s)

p = np.zeros((k / 2 + 1, n + 1), dtype=bool)

p[0] = true

for i in range(1, k/2+1):

for j in range(1, n+1):

p[i][j] = p[i][j-1]

if i >= s[j-1]:

p[i][j] = p[i][j] or p[i-s[j-1]][j-1]

return p[k/2][n]

test_list = [3, 1, 1, 2, 2, 1]

print(find_partition(test_list))

複製**

程式的輸出結果如下

true

複製**

下面的**是程式中的資料{}0

true

true

true

true

true

true

true

1false

false

true

true

true

true

true

2false

false

false

true

true

true

true

3false

true

true

true

true

true

true

4false

false

true

true

true

true

true

5false

false

false

true

true

true

true

上面演算法的時間複雜度為,其中,是輸入多重集合元素的個數,是多重集合中所有元素的和。

如果將問題變成將乙個多重集合分為個和相等的子集,演算法的空間複雜度將為,其中是輸入中最大的值。在這樣的情況下,即使也很難應用這樣的演算法,除非輸入的都是一些小數字。

有一些啟發式演算法可以用來求這個問題的近似解。

想象一下一群孩子分撥玩遊戲的場景,商量好分成幾撥後,每次選出乙個人,加入到人少的那一撥中,貪心演算法的過程類似。在這個問題中,多重集合按降序排列,依次遍歷,每次選出乙個數新增到和值較小的子多重集合中。這個演算法的時間複雜度為。該演算法在實際中能夠得到近似解,但是不保證能得到最優解。比如,輸入多重集合,貪心演算法會將分為和這兩個子多重集合,但是最優解是存在的,比如和。

貪心演算法能得到最優解法的近似解;這個意思是說,設最優解中較大多重集合的和為,貪心演算法輸出兩個多重集合和,那麼有。

python版本的**如下:

def find_partition(input_list):

a, b = ,

sum_a, sum_b = 0, 0

for n in sorted(input_list, reverse=true):

if sum_a < sum_b:

sum_a += n

else:

sum_b += n

return a, b

test_list = [3, 1, 1, 2, 2, 1]

print(find_partition(test_list))

複製**

程式結果輸出如下

([2, 2, 1], [3, 1, 1])

複製**

在這個問題中,上面的解法針對的是的情況,貪心演算法還可用於個分割槽的情況。對的情況,演算法的時間複雜度是,能得到最優解法的近似解。現在,對於數字多重集合劃分問題,我們有乙個多項式時間近似方案,儘管這不是乙個完全多項式時間近似方案。

另一種啟發式演算法是最大差分法,該演算法也被稱之為karmarkar-karp啟發式演算法。最大差分法分兩個階段執行。演算法的第一階段從輸入中取出最大的兩個數,用它們的差來替換它們;迴圈此過程直到只剩下乙個數字。替換表示將這兩個數字放在不同的集合中,但是不確定具體的集合。在第一階段結束時,剩下的數字就是兩個子集和值的差。第二個階段構造出真正的解法。

在這個問題中,差分演算法比貪心演算法效果更好,但對於數字大小和集合大小呈指數關係的情況仍然不適用。

下面的python**實現了演算法的第一階段

from queue import priorityqueue

def karmarkarkarppartition(input_list):

heap = priorityqueue()

for n in input_list:

heap.put((-n, n))

while heap.qsize() > 1:

val1 = heap.get()[1]

val2 = heap.get()[1]

sub_ret = val1 - val2

heap.put((-sub_ret, sub_ret))

return heap.get()[1]

test_list = [3, 1, 1, 2, 2, 1]

print(karmarkarkarppartition(test_list))

複製**

測試輸出為

0

複製**

P NP NPC與NP hard問題的定義

p問題 指的是能在多項式時間內解決的問題。np問題 指的是能在多項式時間內驗證的問題。在此,我們可以看出所有的p問題都屬於np問題,但是p是否等於np呢,至今還未得到驗證,即既證明不了p np,也證明不了p ne np。npc問題 np完全問題 是指np問題中最難的一類問題。證明乙個問題是否是npc...

P NP NPC和NP hard問題的理解

1 p polynomial 問題 可以在以多項式表達的時間內按部就班的按照步驟求出確切解的問題,也就是說它的計算複雜度是乙個多項式。我們通常用的o n o logn o n2 等等類似的都是這類問題。2 np non deterministicpolynomial 問題 有些計算問題是確定性的,比...

關於P NP NPC和NP Hard問題

1 p問題 p中包含的是能在多項式時間內解決的問題,此類問題的時間複雜度不超過o 2 np問題 np中包含的是能在多項式時間內驗證某個解是否正確的問題。比如 1 所有的p問題都是np問題,因為我們總能在多項式時間內驗證給定的某個解是否正確。2 對於某些不屬於p問題的問題,如3 cnf可滿足性問題,給...