CHƯƠNG 19 CÁC BÀI TOÁN NP – KHÓ VÀ NP - ĐẦY ĐỦ Chúng ta đã biết nhiều bài toán, điển hình là bài toán người bán hàng, bài toán balô, bài toán chu trình Hamilton, … Các thuật toán tốt nhấ
Trang 1CHƯƠNG 19 CÁC BÀI TOÁN NP – KHÓ VÀ NP - ĐẦY ĐỦ
Chúng ta đã biết nhiều bài toán, điển hình là bài toán người bán hàng, bài toán balô, bài toán chu trình Hamilton, … Các thuật toán tốt nhất để giải quyết các bài toán này đều có thời gian chạy không phải là thời gian đa thức, chẳng hạn thuật toán quy hoạch động cho bài toán người bán hàng có thời gian chạy O(n22n), … Cho tới nay chưa có ai tìm ra được thuật toán thời gian
đa thức cho bất kỳ bài toán nào trong lớp các bài toán trên Vấn đề đặt ra là
có tồn tại hay không thuật toán thời gian chạy đa thức cho các bài toán trên?
Các vấn đề lý thuyết được trình bày trong chương này không khẳng định rằng, không tồn tại thuật toán thời gian đa thức cho các bài toán trên Điều mà các nhà nghiên cứu đã làm được là chỉ ra rằng, nhiều bài toán chưa
có thuật toán giải trong thời gian đa thức là có liên quan với nhau về mặt tính toán Cụ thể là, chúng ta sẽ thiết lập hai lớp: lớp các bài toán NP – khó (NP-hard) và lớp các bài toán NP- đầy đủ (NP – complete) Một bài toán là NP-đầy đủ có tính chất rằng, nó có thể giải được trong thời gian đa thức nếu
và chỉ nếu tất cả các bài toán NP-đầy đủ khác giải được trong thời gian đa thức Nếu một bài toán NP- khó giải được trong thời gian đa thức thì tất cả các bài toàn NP-đầy đủ giải được trong thời gian đa thức Người ta đã chỉ ra rằng, lớp NP-đầy đủ là lớp con của lớp NP – khó, nhưng có bài toán là NP – khó nhưng không phải là NP-đầy đủ
Các lớp bài toán NP–khó và NP - đầy đủ là rất giàu có Tất cả các bài toán nổi tiếng mà ta đã quen biết (bài toán người bán hàng, bài toán chiếc balô, và rất nhiều bài toán tổ hợp, các bài toán của lý thuyết đồ thị …) đều là
NP – khó
Các lớp NP – khó và NP - đầy đủ liên quan tới sự tính toán không đơn định (nondeterministic computations) Không thể thực hiện được sự tính
Trang 2toán không ổn định trong thực tế, bởi vậy về mặt trực quan, chúng ta có thể phỏng đoán (chưa chứng minh được) rằng, các bài toán NP - đầy đủ hoặc
NP – khó không giải được trong thời gian đa thức
Chúng ta sẽ cố gắng trình bày các vấn đề đã nêu trên một cách đơn giản, không hình thức, không đi sâu vào các chứng minh phức tạp
19.1 THUẬT TOÁN KHÔNG ĐƠN ĐỊNH
Khái niệm thuật toán mà chúng ta sử dụng cho đến nay có tính chất rằng, kết quả thực hiện mỗi phép toán là được xác định duy nhất Thuật toán
với tính chất này được gọi là thuật toán đơn định (deterministic algorithm).
Định nghĩa 1 Lớp P bao gồm tất cả các bài toán giải được bởi thuật
toán đơn định trong thời gian đa thức (tức là tồn tại thuật toán giải quyết nó với thời gian chạy đa thức)
Để xác định lớp NP các bài toán, chúng ta cần phải đưa vào khái niệm
thuật toán không đơn định (nondeterministic algorithm) Sự mở rộng khái
niệm thuật toán đơn định thành khái niệm thuật toán không đơn định cũng hoàn toàn tương tự như khi ta mở rộng khái niêm otomat hữu hạn đơn định thành otomat hữu hạn không đơn định Trong các thuật toán không đơn định chúng ta được phép đưa vào các phép toán mà kết quả của nó không phải là một giá trị được xác định duy nhất mà là một tập hữu hạn các giá trị Các phép toán đó được biểu diễn bởi hàm lựa chọn:
choice(S)
Đây là hàm đa trị, giá trị của nó là các phần tử của tập hữu hạn S Ngoài hàm
choice, để mô tả các thuật toán không đơn định chúng ta đưa vào hai lệnh:
success
failure
Trang 3Các lệnh này là các lệnh dừng, hiệu quả của chúng sẽ được mô tả dưới đây.
Các thuật toán không đơn định được thực hiện như thế nào? Để thực hiện thuật toán không đơn định, chúng ta cần thực hiện các tính toán theo dòng điều khiển được quy định bởi các câu lệnh như khi ta thực hiện thuật toán đơn định, chỉ có một điều khác biệt so với thuật toán đơn định là, khi gặp hàm lựa chọn choice(S) thì sự tính toán được phân thành nhiều nhánh, mỗi nhánh tương ứng với một giá trị được chọn ra từ tập S, tất cả các nhánh này sẽ làm việc đồng thời và độc lập với nhau Mỗi nhánh tính toán đó khi gặp một hàm lựa chọn khác choice(S’) lại được phân thành nhiều nhánh tính toán khác Và như vậy, khi thực hiện thuật toán không đơn định, chúng ta cần phải thực hiện đồng thời và độc lập nhiều đường tính toán (được tạo thành từ các nhánh tương ứng với các lựa chọn) Do đó, ta có thể quan niệm rằng, thuật toán không đơn định mô tả sự tính toán song song không hạn chế Khi mà một đường tính toán gặp lệnh success, thì có nghĩa là đường tính toán đó đã được tạo thành từ các lựa chọn đúng đắn và đã thành công cho ra nghiệm của bài toán, khi đó tất cả các đường tính toán đều dừng làm việc Còn nếu một đường tính toán gặp lệnh failure, thì có nghĩa là đường tính toán này đã thất bại, không cho ra nghiệm của bài toán, và chỉ riêng đường này dừng làm việc Máy có khả năng thực hiện thuật toán không đơn
định sẽ được gọi là máy không đơn định (nondeterministic machine).
Không tồn tại các máy không đơn định trong thực tế Sau đây chúng ta sẽ đưa ra một vài ví dụ về thuật toán không đơn định
Ví dụ 1 Xét bài toán tìm xem phần tử x có trong mảng A[0 … n - 1],
n ≥ 1, hay không ? Nếu có ta cần in ra chỉ số i mà A[i] = x, nếu không thì in
ra n Thuật toán không đơn định là như sau:
Search (x, A, n)
// Tìm x trong mảng A[0… n - 1]
{
i = choice( 0: n – 1);
if (A[i] = = x)
Trang 4{
print(i);
success;
}
else {
print(n);
failure ;
}
}
Chú ý rằng, lệnh gán i = choice( 0 : n – 1) cho kết quả là biến i được gán một trong các giá trị trong đoạn [0 … n - 1]
Ví dụ 2 Chúng ta đưa ra thuật toán không đơn định để sắp xếp mảng
A[0 … n – 1] theo thứ tự không giảm Trong thuật toán ta sử dụng mảng phụ B[0 … n - 1]
Sort (A, n)
// Sắp xếp mảng A[0 … n - 1], n ≥ 1
{
(1) for ( i = 0 ; i < n ; i + + )
B[i] = ∞ ;
(2) for ( i = 0 ; i < n ; i + +)
{
(3) k = choice( 0 : n – 1);
(4) if (B[k] ≠∞ )
failure ;
else
B[k] = A[i] ;
} (5) for ( i = 0 ; i < n-1 ; i + +)
if (B[i] > B[i + 1])
Trang 5failure;
(6) print (B);
// in ra mảng B đã được sắp theo thứ tự không giảm
(7) success;
}
Lệnh lặp (1) khởi tạo mảng B chứa một giá trị khác với tất cả các giá trị trong mảng A Lệnh lặp (2) thực hiện đặt mỗi giá trị A[i] trong mảng A vào mảng B tại chỉ số k, với k được lựa chọn không đơn định bởi lệnh (3) Lệnh (4) kiểm tra xem B[k] đã chứa một giá trị trong mảng A hay chưa Sau khi thực hiện lệnh lặp (2), nhánh tính toán không gặp lệnh failure sẽ cho kết quả mảng B chứa các giá trị là hoán vị của các giá trị trong mảng A Lệnh (5) kiểm tra các giá trị trong mảng B có thoả mãn thứ tự không giảm hay không
Bây giờ chúng ta xác định thời gian thực hiện thuật toán không đơn định Thời gian này được xác định là thời gian thực hiện đường tính toán ngắn nhất dẫn tới sự kết thúc thành công (lệnh success) Khi đánh giá thời gian chạy của thuật toán không đơn định, chúng ta có thể sử dụng các kỹ thuật đánh giá thời gian chạy của thuật toán đơn định đã trình bày trong chương 15, chỉ cần lưu ý rằng, thời gian thực hiện hàm choice(S) và các lệnh success và failure là O(1) Chẳng hạn, dễ dàng thấy rằng, thuật toán không đơn định tìm phần tử x trong mảng A[0 … n - 1] (ví dụ 1) có thời gian chạy
là O(1), trong khi đó thuật toán đơn định (tìm kiếm tuần tự) cần thời gian O(n)
Bây giờ ta đánh giá thời gian chạy của thuật toán không đơn định sắp xếp mảng A[0 … n - 1] (ví dụ 2) Trong thuật toán này, mỗi lệnh lặp (1), (2), (5) và lệnh (6) cần thời gian O(n), và do đó thời gian chạy của thuật toán không đơn định này là O(n) Trong chương 17 chúng ta đã thấy rằng, tất cả các thuật toán đơn định tốt nhất để sắp xếp mảng đều đòi hỏi thời gian O(nlogn)
Trang 6Khả năng tính toán của thuật toán không đơn định là rất mạnh Nhiều bài toán cho tới nay người ta mới chỉ tìm ra thuật toán đơn định với thời gian
mũ để giải quyết, nhưng chúng ta có thể dễ dàng đưa ra thuật toán không đơn định với thời gian đa thức cho các bài toán đó
Định nghĩa 2 Lớp NP bao gồm tất cả các bài toán có thể giải được
bởi thuật toán không đơn định trong thời gian đa thức
Bởi vì thuật toán đơn định là trường hợp đặc biệt của thuật toán không đơn định, do đó lớp P là lớp con của lớp NP Nhưng cho tới nay người ta vẫn chưa biêt P = NP hay P ≠ NP? Tức là, có phải tất cả các bài toán giải được bởi thuật toán không đơn định trong thời gian đa thức đều có thể giải được bởi thuật toán đơn định trong thời gian đa thức, hay là có bài toán giải được bởi thuật toán không đơn định trong thời gian đa thức, nhưng không tồn tại thuật toán đơn định với thời gian đa thức để giải quyết nó? Đây là vấn
đề chưa giải quyết được, nổi tiếng nhất của khoa học máy tính
19.2 CÁC BÀI TOÁN NP–KHÓ VÀ NP- ĐẦY ĐỦ
Trong quá trình nghiên cứu để tìm câu trả lời cho vấn đề đã nêu trên,
S Cook đã phát hiện ra một bài toán thuộc lớp NP mà nếu ta tìm được thuật toán đơn định với thời gian đa thức để giải quyết nó thì P = NP
Bài toán thoả được trong logic mệnh đề
Giả sử x1, x2, … là các biến boolean (giá trị của chúng chỉ có thể là true hoặc false) Ta ký hiệu xi là phủ định của xi Litaral là một biến hoặc phủ định của một biến Một câu tuyển (clause) là tuyển của các literal, chẳng hạn x1 ∨ x2∨ x3 là một câu tuyển Một công thức dạng chuẩn hội là hội của các câu tuyển Chẳng hạn, các công thức sau là các công thức dạng chuẩn hội:
(x1∨ x2 ∨ x3) ∧ ( x2 ∨ x3) ∧ ( x1∨ x3) (1)
(x1∨ x2) ∧ ( x1) ∧ ( x2) (2)
Trang 7Chúng ta đã biết rằng, mọi công thức trong logic mệnh đề đều có thể biến đổi đưa về công thức dạng chuẩn hội Một công thức được gọi là thoả được (satisfiable) nếu có một cách gán giá trị chân lý cho các biến sao cho công thức nhận giá trị true Nếu với mọi cách gán giá trị chân lý cho các biến, công thức đều nhận giá trị false thì nó được xem là không thoả được
Ví dụ, công thức (1) là thoả được, bởi vì với x1 = true, x2 = false, x3 = false công thức sẽ đúng; công thức (2) là không thoả được
Bài toán thoả được (satisfiability problem) là như sau: xác định công thức dạng chuẩn hội có thoả được hay không?
Giả sử E = E(x1 , … , xn) là công thức dạng chuẩn hội của các biến x1,
…, xn Thuật toán không đơn định để kiểm tra E có thoả được hay không là rất đơn giản: ta chỉ cần lựa chọn (không đơn định) một trong 2n
khả năng gán giá trị chân lý cho n biến và tính giá trị của công thức E tương ứng với mỗi cách gán Thuật toán không đơn định là như sau:
Eval (E, n)
// Xác định xem công thức E chứa n biến có thoả được không
{
for ( i = 1 ; i < = n ; i + +)
xi = choice (true, false);
if ( giá trị của E là true )
success ; // thoả được
else
failure ;
}
Chúng ta đánh giá thời gian thực hiện thuật toán không đơn định Eval Thời gian để lựa chọn giá trị chân lý cho các biến x i (i = 1, …, n) (lệnh lặp for) là O(n) Thời gian để tính giá trị của E tương ứng với các giá trị đã lựa chọn của các biến là O(kn), trong đó k là số phép hội trong công thức E Do
Trang 8đó thời gian chạy của Eval là O(kn) Như vậy, bài toán thoả được thuộc lớp NP
Định lý (S Cook) Bài toán thoả được thuộc lớp P nếu và chỉ nếu P =
NP
Chứng minh định lý này rất phức tạp, chúng ta không đưa ra Bây giờ chúng ta xác định hai lớp bài toán: lớp NP – khó và lớp NP - đầy đủ
Với ý tưởng sử dụng thuật toán giải một bài toán để nhận được thuật toán giải các bài toán khác, chúng ta có định nghĩa sau:
Định nghĩa 3 Ta nói bài toán B1 quy về bài toán B2 (ký hiệu B1 <<
B2) nếu ta có thể biến đổi trong thời gian đa thức đầu vào của bài toán B1
(input1) thành đầu vào của bài toán B2 (input2) sao cho ta có thể nhận được nghiệm của bài toán B1 (output1) từ nghiệm của bài toán B2 (output2) bởi phép biến đổi trong thời gian đa thức
Từ định nghĩa trên, ta suy ra lược đồ chứng minh bài toán B1 quy về bài toán B2 là như sau:
input1 input2 output2 output1
Dễ dàng thấy rằng, quan hệ “quy về” có tính bắc cầu, tức là nếu B1 <<
B2 và B2 << B3 thì B1 << B3 Cũng rõ ràng rằng, nếu B1 quy về B2 và B2 là giải được trong thời gian đa thức thì B1 cũng giải được trong thời gian đa thức
Định nghĩa 4 Một bài toán là NP – khó nếu bài toán thoả được quy
về bài toán đó Một bài toán là NP - đầy đủ nếu nó là NP- khó và nó thuộc lớp NP
Theo định nghĩa trên, bài toán thoả được là NP - đầy đủ Làm thế nào
để chứng minh một bài toán là NP- khó ? Do quan hệ << có tính bắc cầu, để
Phép biến đổi trong thời gian
đa thức
Thuật toán giải
B 2
Phép biến đổi trong thời gian
đa thức
Trang 9chứng minh bài toán B là NP- khó, ta chỉ cần chứng minh một bài toán A nào đó mà ta đã biết là NP – khó qui về bài toán B, A << B
19.3 MỘT SỐ BÀI TOÁN NP – KHÓ
Mục này trình bày một số bài toán NP – khó trong lý thuyết đồ thị Nhắc lại rằng, để chứng minh một bài toán B là NP – khó, chúng ta có thể chứng minh bài toán thoả được quy về bài toán B, hoặc chứng minh rằng, một bài toán A nào đó mà ta đã biết là NP – khó quy về bài toán B
Bài toán đồ thị con đầy đủ
Giả sử G = (V, E) là đồ thị vô hướng, đồ thị G’ = (V’, E’) được gọi là
đồ thị con đầy đủ của đồ thị G nếu V’ ⊆ V và E’ ⊆ E, và với mọi cặp đỉnh u,
v ∈V’ tồn tại cạnh (u, v) ∈ E’
Định lý 1 Bài toán “xác định một đồ thị vô hướng G = (V, E) có đồ
thị con đầy đủ k đỉnh hay không” là bài toán NP - đầy đủ
Chứng minh Trước hết ta chứng minh bài toán thuộc lớp NP Thuật toán không đơn định với thời gian đa thức để xác định một đồ thị vô hướng
n đỉnh G có chứa đồ thị con đầy đủ k đỉnh (k ≤ n) là như sau Đầu tiên ta chọn (không đơn định) ra k đỉnh từ n đỉnh, sau đó kiểm tra xem k đỉnh đã chọn ra có tạo thành đồ thị con đầy đủ không Việc kiểm tra này chỉ đòi hỏi thời gian O(k2) Điều đó chứng tỏ rằng, bài toán thuộc lớp NP
Để chứng minh bài toán là NP – khó, chúng ta sẽ chứng minh bài toán thoả được quy về nó
Giả sử F = C1 ∧ C2 ∧ … ∧ Ck là công thức logic mệnh đề dưới dạng chuẩn hội, F là hội của k câu tuyển Ci(i = 1, …, n) Từ công thức này ta xây dựng đồ thị vô hướng G = (V, E), với tập đỉnh V và tập cạnh E được xác định như sau:
Trang 10V = { ( α , i ) , trong đó α là một literal trong câu tuyển Ci }
E = { ( ( α , i ) , ( β , j ) ) , trong đó i ≠ j và α ≠β }
Chúng ta sẽ chứng minh rằng, công thức F là thoả được nếu và chỉ nếu đồ thị G có đồ thị con đầy đủ k đỉnh Thật vậy, nếu công thức F thoả được thì tồn tại cách gán giá trị chân lý sao cho mỗi câu tuyển Ci chứa một literal α được gán true với i = 1, 2, …, k Trong đồ thị G, ta chọn ra k đỉnh (α, i) với i = 1, 2, …, k và α là literal được gán true Với hai đỉnh bất kỳ được chọn ra (α, i) và (β, j), vì α và β cùng được gán true, nên α ≠ β Do
đó k đỉnh đã chọn ra đó tạo thành đồ thị con đầy đủ của đồ thị G Ngược lại, giả sử đồ thị G chứa đồ thị con đầy đủ k đỉnh Ta đưa ra cách gán giá trị chân lý cho các biến trong công thức F như sau Nếu (α, i) là một đỉnh của
đồ thị con đầy đủ và α là biến x thì x được gán true, còn nếu α là phủ đỉnh của biến y thì y được gán false Với cách gán này tất cả các câu tuyển Ci đều chứa một literal có giá trị true và do đó công thức F nhận giá trị true, tức là F thoả được Mặt khác, việc xây dựng đồ thị G từ công thức F và việc xây dựng cách gán giá trị chân lý cho các biến của công thức F từ đồ thị con đầy
đủ của đồ thị G, dễ dàng thấy, chỉ đòi hỏi thời gian đa thức Do đó bài toán
là NP - đầy đủ
A B
Hình 19.1 Đồ thị và chu trình Hamilton