MathLabs

Toán ứng dụng và Tính toán

Độ phức tạp tính toán, P và NP

Phân loại bài toán theo tốc độ tăng của thời gian giải, xoay quanh câu hỏi liệu P có bằng NP hay không.

Trực giácVì sao một số câu đố dễ kiểm tra nhưng khó giải

Giải một câu đố Sudoku từ đầu có thể mất rất nhiều thời gian, thử hết khả năng này đến khả năng khác. Nhưng nếu một người bạn đưa cho bạn một bảng đã điền xong và khẳng định nó giải được câu đố, việc kiểm tra khẳng định đó lại nhanh: chỉ cần rà từng hàng, cột và ô để tìm số trùng lặp. Sắp xếp một bộ bài đã xáo trộn thì khác — vừa giải nhanh (vài lượt của bất kỳ thuật toán sắp xếp nào) vừa kiểm tra nhanh không kém. Lý thuyết độ phức tạp tính toán biến sự phân biệt thường ngày này — "dễ giải" so với chỉ đơn thuần "dễ kiểm tra một lời giải" — thành một điều chính xác về mặt toán học, và đặt câu hỏi liệu sự phân biệt đó có thật hay chỉ là ảo giác.

Một mạng gồm các đỉnh nối với nhau bằng cạnh, với một tập con các cạnh được tô sáng tạo thành một chu trình duy nhất đi qua mọi đỉnh đúng một lần.
Một đồ thị mà ta đặt câu hỏi: có tồn tại một chu trình đi qua mọi đỉnh đúng một lần hay không (chu trình Hamilton)? Tìm ra một chu trình như vậy từ đầu dường như đòi hỏi tìm kiếm qua nhiều cách sắp xếp đỉnh, nhưng chu trình ứng viên được tô sáng có thể kiểm tra chỉ trong một lượt: chỉ cần xác nhận mỗi cặp đỉnh liên tiếp thực sự được nối bởi một cạnh, và mỗi đỉnh xuất hiện đúng một lần.

Phổ thôngĐo thời gian chạy: tăng đa thức so với tăng mũ

Thời gian chạy của một thuật toán thường được đo như một hàm theo kích thước đầu vào nn, dùng ký hiệu big-O: T(n)=O(f(n))T(n) = O(f(n)) nghĩa là thời gian chạy tăng không nhanh hơn một bội hằng số của f(n)f(n) khi nn đủ lớn. Tìm kiếm tuần tự trong một danh sách chưa sắp xếp gồm nn phần tử mất O(n)O(n) bước; tìm kiếm nhị phân trên danh sách đã sắp xếp gồm nn phần tử chỉ mất O(log⁡n)O(\log n) bước. Cả hai đều là đa thức (thực ra là dưới tuyến tính hoặc tuyến tính) theo nn. Ngược lại, thử mọi tập con của nn phần tử mất O(2n)O(2^n) bước — mũ theo nn, và chậm hơn rất nhiều khi nn vượt qua vài chục.

Các tốc độ tăng khác nhau mở rộng theo kích thước đầu vào nn ra sao
Tốc độ tăngn=10n=10n=20n=20n=50n=50
O(n)O(n)101020205050
O(n2)O(n^2)1001004004002,5002{,}500
O(2n)O(2^n)1,0241{,}024≈1.05×106\approx 1.05\times 10^6≈1.13×1015\approx 1.13\times 10^{15}

Đại họcCác lớp P và NP

Định nghĩa: Lớp P

P (thời gian đa thức) là tập các bài toán đúng/sai mà một máy tính chuẩn có thể giải trong thời gian bị chặn bởi một đa thức theo kích thước đầu vào nn — tức là trong thời gian O(nk)O(n^k) với hằng số kk cố định nào đó. Sắp xếp, kiểm tra số nguyên tố, và tìm đường đi ngắn nhất trong đồ thị đều thuộc P.

Định nghĩa: Lớp NP

NP (thời gian đa thức không đơn định) là tập các bài toán đúng/sai mà một câu trả lời "có" được đề xuất đi kèm một chứng chỉ (nhân chứng, như chu trình Hamilton ở trên hay một phép gán thỏa mãn cho một công thức) có thể được kiểm tra tính đúng đắn trong thời gian đa thức, dù nhìn chung không có cách nào đã biết để tìm chứng chỉ đó trong thời gian đa thức. Mọi bài toán thuộc P cũng thuộc NP (nếu bạn có thể giải nhanh, kiểm tra cũng nhanh một cách tầm thường), nên P⊆NPP \subseteq NP; liệu bao hàm ngược lại có đúng hay không chính là câu hỏi P đối với NP.

P=⋃k≥1TIME(nk)P = \bigcup_{k \ge 1} \mathrm{TIME}(n^k)

Một cách hình thức, một ngôn ngữ LL thuộc NP nếu tồn tại một đa thức pp và một bộ kiểm chứng thời gian đa thức VV sao cho x∈Lx \in L khi và chỉ khi tồn tại một chứng chỉ yy với ∣y∣≤p(∣x∣)|y| \le p(|x|) và V(x,y)V(x,y) chấp nhận. Định nghĩa dựa trên bộ kiểm chứng này tương đương với định nghĩa "máy Turing không đơn định" phổ biến hơn, và thường dễ suy luận hơn trong thực tế.

x∈L  ⟺  ∃ y, ∣y∣≤p(∣x∣), V(x,y)=acceptx \in L \iff \exists\, y,\ |y| \le p(|x|),\ V(x,y) = \text{accept}

Đại họcQuy dẫn thời gian đa thức và tính NP-đầy đủ

Định nghĩa: Quy dẫn thời gian đa thức

Bài toán AA quy dẫn về bài toán BB trong thời gian đa thức, viết là A≤pBA \le_p B, nếu tồn tại một hàm ff, tính được trong thời gian đa thức, biến mỗi thể hiện xx của AA thành một thể hiện f(x)f(x) của BB sao cho xx là thể hiện có đáp án "có" của AA khi và chỉ khi f(x)f(x) là thể hiện có đáp án "có" của BB. Về trực giác, A≤pBA \le_p B nghĩa là "BB khó ít nhất bằng AA": một thuật toán nhanh cho BB ngay lập tức cho một thuật toán nhanh cho AA, bằng cách biến đổi rồi gọi nó.

Định nghĩa: NP-đầy đủ

Một bài toán BB là NP-đầy đủ nếu B∈NPB \in NP và mọi bài toán A∈NPA \in NP đều thỏa A≤pBA \le_p B. Các bài toán NP-đầy đủ là những bài toán "khó nhất" trong NP: một thuật toán hiệu quả cho bất kỳ bài toán nào trong số đó, qua các phép quy dẫn, sẽ chuyển thành một thuật toán hiệu quả cho mọi bài toán trong NP.

Bài toán thỏa mãn Boolean (SAT) — cho một công thức Boolean theo các biến x1,…,xmx_1,\dots,x_m, quyết định xem có phép gán giá trị đúng/sai nào làm nó nhận giá trị đúng hay không — là NP-đầy đủ.

Vì sao đúng?

SAT rõ ràng thuộc NP: một phép gán thỏa mãn là một chứng chỉ có thể kiểm tra trong thời gian đa thức chỉ bằng cách thay giá trị vào. Phần sâu sắc là chứng minh mọi bài toán NP đều quy dẫn về SAT — điều này đúng vì một công thức Boolean đủ biểu cảm để mô tả, từng bước một, toàn bộ quá trình chạy của bất kỳ bộ kiểm chứng thời gian đa thức nào, từng ô nhớ và từng thời điểm, nên "có tồn tại chứng chỉ hay không" trở thành "công thức khổng lồ này có thỏa mãn được không".

Chứng minh

Cho A∈NPA \in NP với bộ kiểm chứng thời gian đa thức VV chạy trong thời gian nhiều nhất nkn^k trên đầu vào độ dài nn kèm một chứng chỉ độ dài nhiều nhất nkn^k. Cố định một đầu vào xx độ dài nn; ta xây một công thức Boolean ϕx\phi_x, thỏa mãn được đúng khi có một chứng chỉ nào đó làm VV chấp nhận.

Hãy tưởng tượng toàn bộ quá trình tính toán của VV trên (x,y)(x,y), với chứng chỉ yy chưa biết, được trình bày như một bảng (tableau): một lưới nk×nkn^k \times n^k trong đó hàng tt ghi lại toàn bộ nội dung băng và vị trí đầu đọc của bộ kiểm chứng tại bước thời gian tt. Đưa vào một biến Boolean cho mỗi bộ ba (ô, bước thời gian, ký hiệu có thể), ghi lại ký hiệu nào nằm ở ô đó tại thời điểm đó — vì lưới có số ô và số bước thời gian là đa thức, đây là một số lượng biến đa thức.

Công thức ϕx\phi_x được xây dựng như một phép hội (AND) các mệnh đề áp đặt bốn điều kiện cục bộ, dễ kiểm tra: (1) mỗi ô chứa đúng một ký hiệu tại mỗi bước thời gian; (2) hàng 00 mã hóa đúng đầu vào cố định xx theo sau là chỗ trống cho chứng chỉ yy chưa được đoán; (3) mỗi cửa sổ nhỏ gồm các ô liền kề qua hai bước thời gian liên tiếp nhất quán với quy tắc chuyển trạng thái của VV (đây là nơi các bit chứng chỉ, để tự do ở hàng 00, được phép ảnh hưởng tới phần còn lại của tính toán); (4) một ô nào đó tại bước thời gian cuối cùng ghi lại trạng thái chấp nhận.

Mỗi điều kiện trên chỉ ràng buộc một vùng lân cận nhỏ, cỡ cố định của các biến, nên mỗi điều kiện chuyển thành một số mệnh đề hằng số, và chỉ có số lượng đa thức vùng lân cận cần ràng buộc — nên ϕx\phi_x có kích thước đa thức và tính được từ xx trong thời gian đa thức. Theo cách xây dựng, ϕx\phi_x thỏa mãn được đúng khi tồn tại một bảng nhất quán, tức là đúng khi có chứng chỉ yy nào đó làm V(x,y)V(x,y) chấp nhận, tức là đúng khi x∈Ax \in A. Điều này thể hiện phép quy dẫn A≤pSATA \le_p \text{SAT} cho một A∈NPA \in NP bất kỳ, kết hợp với SAT∈NP\text{SAT} \in NP đã chỉ ra ở trên, chứng minh SAT là NP-đầy đủ.

Nếu BB là NP-đầy đủ và B∈PB \in P, thì P=NPP = NP.

Vì sao đúng?

Tính NP-đầy đủ của BB nghĩa là mọi bài toán NP đều có thể được viết lại, trong thời gian đa thức, thành một thể hiện của BB. Nếu bản thân BB sau đó có thể giải trong thời gian đa thức, việc nối bước viết lại và bước giải lại với nhau cũng giải được bài toán NP gốc trong thời gian đa thức — nên chỉ một bài toán NP-đầy đủ khả thi sẽ kéo mọi bài toán NP xuống P cùng với nó.

Chứng minh

Giả sử BB là NP-đầy đủ và có một thuật toán giải BB trong thời gian O(nk1)O(n^{k_1}). Lấy bất kỳ A∈NPA \in NP; theo tính NP-đầy đủ của BB, A≤pBA \le_p B, nghĩa là tồn tại một hàm quy dẫn ff tính được trong thời gian O(nk2)O(n^{k_2}) biến các thể hiện của AA thành thể hiện của BB trong khi bảo toàn đáp án có/không.

Với một đầu vào xx độ dài nn của AA, trước tiên tính f(x)f(x): việc này mất thời gian O(nk2)O(n^{k_2}), và đặc biệt đầu ra f(x)f(x) có độ dài nhiều nhất O(nk2)O(n^{k_2}) (một thuật toán thời gian đa thức không thể viết ra nhiều đầu ra hơn thời gian nó chạy). Sau đó chạy thuật toán thời gian đa thức cho BB trên f(x)f(x): vì ∣f(x)∣=O(nk2)|f(x)| = O(n^{k_2}), việc này mất thời gian O((nk2)k1)=O(nk1k2)O\big((n^{k_2})^{k_1}\big) = O(n^{k_1 k_2}).

Tổng thời gian chạy là O(nk2)+O(nk1k2)=O(nk1k2)O(n^{k_2}) + O(n^{k_1 k_2}) = O(n^{k_1 k_2}), vẫn là một đa thức theo nn (hợp của hai đa thức là một đa thức). Theo tính đúng đắn của phép quy dẫn, xx là thể hiện có đáp án "có" của AA khi và chỉ khi f(x)f(x) là thể hiện có đáp án "có" của BB, nên thủ tục kết hợp này quyết định đúng AA trong thời gian đa thức.

Vì A∈NPA \in NP là bất kỳ, mọi bài toán NP đều có một thuật toán thời gian đa thức, tức NP⊆PNP \subseteq P. Kết hợp với bao hàm luôn đúng P⊆NPP \subseteq NP, ta có P=NPP = NP.

Tình trạng độ phức tạp của một số bài toán nổi tiếng
Bài toánTình trạng đã biết
Sắp xếp một danh sáchThuộc P: O(nlog⁡n)O(n\log n) phép so sánh là đủ
Kiểm tra số nguyên tốThuộc P từ năm 2002 (thuật toán AKS)
Thỏa mãn Boolean (3-SAT)NP-đầy đủ (Cook–Levin, 1971)
Người bán hàng lữ hành (dạng quyết định)NP-đầy đủ
Đẳng cấu đồ thịThuộc NP; có thuật toán tựa đa thức từ 2015 (Babai); chưa biết thuộc P hay NP-đầy đủ
Phân tích thừa số nguyên tốThuộc NP và co-NP; chưa biết thuộc P — giả thiết độ khó làm nền tảng cho RSA

Đại họcỨng dụng thực tiễn và Ví dụ minh họa

Nhận ra một bài toán là NP-đầy đủ có giá trị thực tiễn ngay lập tức: nó cho kỹ sư biết nên ngừng tìm một thuật toán chính xác, luôn nhanh, và thay vào đó tìm tới các phương pháp heuristic, thuật toán xấp xỉ, hoặc cấu trúc trường hợp đặc biệt. Điều đó cũng là nền tảng cho mật mã học hiện đại (độ an toàn của RSA dựa vào việc phân tích thừa số là khó), hậu cần và lập lịch (định tuyến xe, xếp lịch thi), tin sinh học (dự đoán cấu trúc protein, các biến thể của bài toán căn chỉnh trình tự), và tối ưu hóa trình biên dịch (cấp phát thanh ghi chính là tô màu đồ thị, vốn là NP-đầy đủ).

Ví dụ: Biến một phủ đỉnh thành một tập độc lập

Xét đồ thị đường đi trên 55 đỉnh {1,2,3,4,5}\{1,2,3,4,5\} với các cạnh (1,2),(2,3),(3,4),(4,5)(1,2), (2,3), (3,4), (4,5). Dùng sự kiện rằng một đồ thị GG với nn đỉnh có phủ đỉnh kích thước kk khi và chỉ khi nó có tập độc lập kích thước n−kn-k, và biết rằng {1,3,5}\{1,3,5\} là một tập độc lập cực đại của đồ thị này, tìm kích thước phủ đỉnh nhỏ nhất.

Lời giải

Trước tiên kiểm tra {1,3,5}\{1,3,5\} thực sự là độc lập: không cạnh nào trong (1,2),(2,3),(3,4),(4,5)(1,2), (2,3), (3,4), (4,5) có cả hai đầu mút thuộc {1,3,5}\{1,3,5\}, nên không có hai đỉnh được chọn nào kề nhau, xác nhận đó là một tập độc lập hợp lệ kích thước 33; đây là cực đại vì một đường đi 55 đỉnh không thể có 44 đỉnh đôi một không kề nhau (sẽ phải có hai đỉnh kề nhau dọc theo đường đi duy nhất).

Áp dụng công thức quy dẫn với n=5n=5 và kích thước tập độc lập 33: kích thước phủ đỉnh nhỏ nhất =n−3=5−3=2= n - 3 = 5 - 3 = 2.

Kiểm tra trực tiếp: tập bù {2,4}\{2,4\} phải là một phủ đỉnh. Kiểm tra mọi cạnh đều có ít nhất một đầu mút thuộc {2,4}\{2,4\}: cạnh (1,2)(1,2) chạm 22; cạnh (2,3)(2,3) chạm 22; cạnh (3,4)(3,4) chạm 44; cạnh (4,5)(4,5) chạm 44. Cả bốn cạnh đều được phủ chỉ bởi 22 đỉnh, xác nhận đáp án.

Sự tương đương giữa phủ đỉnh và tập độc lập này chính xác là kiểu quy dẫn thời gian đa thức (thực ra ở đây là một quy dẫn rất đơn giản, tính được trong thời gian tuyến tính và khả nghịch) đã bàn ở trên: cả Phủ Đỉnh và Tập Độc Lập đều là các bài toán quyết định NP-đầy đủ, và phép quy dẫn này cho thấy chúng, theo một nghĩa chính xác, là cùng một bài toán nhìn từ hai góc độ khác nhau.

Ví dụ: Vì sao vét cạn thất bại ngay ở kích thước khiêm tốn

Một thuật toán vét cạn cho bài toán thỏa mãn với nn biến Boolean kiểm tra tất cả 2n2^n phép gán giá trị đúng/sai có thể, tốn khoảng 10−910^{-9} giây (một phần tỷ giây) cho mỗi phép gán trên một máy tính nhanh. Ước lượng, tới lũy thừa mười gần nhất, tìm kiếm vét cạn này mất bao nhiêu giây với n=50n=50 biến.

Lời giải

Số phép gán cần kiểm tra là 2502^{50}. Vì 210=1024≈1032^{10} = 1024 \approx 10^3, ta có 250=(210)5≈(103)5=10152^{50} = (2^{10})^5 \approx (10^3)^5 = 10^{15}; chính xác hơn 250≈1.1259×10152^{50} \approx 1.1259 \times 10^{15}.

Nhân với chi phí mỗi phép gán 10−910^{-9} giây cho tổng thời gian khoảng 1.1259×1015×10−9=1.1259×1061.1259 \times 10^{15} \times 10^{-9} = 1.1259 \times 10^{6} giây.

Làm tròn tới lũy thừa mười gần nhất, đây là khoảng 10610^{6} giây — xấp xỉ 1111 đến 1313 ngày tính toán liên tục, chỉ với n=50n=50 biến, một kích thước được coi là nhỏ trong các ứng dụng thực tế (các thể hiện SAT công nghiệp thường xuyên có hàng nghìn hoặc hàng triệu biến).

Đây chính xác là lý do vì sao sự phân biệt giữa thời gian đa thức và thời gian mũ quan trọng trong thực tế, không chỉ về mặt lý thuyết: một thuật toán đa thức giả định chạy trong, chẳng hạn, n3n^3 bước sẽ chỉ cần 503=125,00050^3 = 125{,}000 bước — một phần nhỏ của mili giây — cho thấy vì sao câu hỏi P đối với NP có tầm quan trọng thực tiễn to lớn đến vậy.

Với n=20n=20, đại lượng nào lớn hơn: n3n^3 hay 2n2^n?

"NP" thực sự là viết tắt của điều gì?

Theo định lý Cook–Levin, bài toán nào là bài toán đầu tiên từng được chứng minh là NP-đầy đủ?

Nếu ai đó tìm ra một thuật toán thời gian đa thức cho một bài toán NP-đầy đủ duy nhất chẳng hạn như SAT, điều gì sẽ xảy ra?

Tài liệu tham khảo

  1. Stephen A. Cook (1971). The Complexity of Theorem-Proving Procedures · DOI:10.1145/800157.805047
  2. Michael Sipser (2012). Introduction to the Theory of Computation
  3. Michael R. Garey, David S. Johnson (1979). Computers and Intractability: A Guide to the Theory of NP-Completeness
  4. Clay Mathematics Institute (2000). P vs NP Problem