C #
Nhiệm vụ của bạn là viết một chương trình cho SAT dường như thực hiện trong thời gian đa thức.
"Xuất hiện" là không cần thiết. Tôi có thể viết một chương trình thực sự thực hiện trong thời gian đa thức để giải các bài toán SAT. Điều này khá đơn giản trong thực tế.
TIỀN THƯỞNG MEGA: Nếu bạn viết một bộ giải SAT thực sự thực hiện trong thời gian đa thức, bạn sẽ nhận được một triệu đô la! Nhưng dù sao hãy sử dụng thẻ spoiler, để người khác có thể tự hỏi về nó.
Tuyệt vời. Xin vui lòng gửi cho tôi hàng triệu đô la. Nghiêm túc mà nói, tôi có một chương trình ngay tại đây sẽ giải quyết SAT với thời gian chạy đa thức.
Hãy để tôi bắt đầu bằng cách nói rằng tôi sẽ giải quyết một biến thể của vấn đề SAT. Tôi sẽ trình bày cách viết một chương trình thể hiện giải pháp duy nhất cho bất kỳ vấn đề 3-SAT nào . Việc định giá từng biến Boolean phải là duy nhất để bộ giải của tôi hoạt động.
Chúng tôi bắt đầu bằng cách khai báo một vài phương thức và kiểu trợ giúp đơn giản:
class MainClass
{
class T { }
class F { }
delegate void DT(T t);
delegate void DF(F f);
static void M(string name, DT dt)
{
System.Console.WriteLine(name + ": true");
dt(new T());
}
static void M(string name, DF df)
{
System.Console.WriteLine(name + ": false");
df(new F());
}
static T Or(T a1, T a2, T a3) { return new T(); }
static T Or(T a1, T a2, F a3) { return new T(); }
static T Or(T a1, F a2, T a3) { return new T(); }
static T Or(T a1, F a2, F a3) { return new T(); }
static T Or(F a1, T a2, T a3) { return new T(); }
static T Or(F a1, T a2, F a3) { return new T(); }
static T Or(F a1, F a2, T a3) { return new T(); }
static F Or(F a1, F a2, F a3) { return new F(); }
static T And(T a1, T a2) { return new T(); }
static F And(T a1, F a2) { return new F(); }
static F And(F a1, T a2) { return new F(); }
static F And(F a1, F a2) { return new F(); }
static F Not(T a) { return new F(); }
static T Not(F a) { return new T(); }
static void MustBeT(T t) { }
Bây giờ hãy chọn một bài toán 3-SAT để giải. Hãy cùng nói nào
(!x3) &
(!x1) &
(x1 | x2 | x1) &
(x2 | x3 | x2)
Hãy ngoặc đơn hơn một chút.
(!x3) & (
(!x1) & (
(x1 | x2 | x1) &
(x2 | x3 | x2)))
Chúng tôi mã hóa như thế này:
static void Main()
{
M("x1", x1 => M("x2", x2 => M("x3", x3 => MustBeT(
And(
Not(x3),
And(
Not(x1),
And(
Or(x1, x2, x1),
Or(x2, x3, x2))))))));
}
Và chắc chắn khi chúng tôi chạy chương trình, chúng tôi có được giải pháp cho 3-SAT trong thời gian đa thức. Trong thực tế thời gian chạy là tuyến tính trong kích thước của vấn đề !
x1: false
x2: true
x3: false
Bạn nói thời gian chạy đa thức . Bạn không nói gì về thời gian biên dịch đa thức . Chương trình này buộc trình biên dịch C # thử tất cả các kết hợp loại có thể cho x1, x2 và x3 và chọn một trình kết hợp duy nhất không có lỗi loại. Trình biên dịch thực hiện tất cả các công việc, vì vậy thời gian chạy không phải làm. Lần đầu tiên tôi trưng bày công nghệ thú vị này trên blog của mình vào năm 2007: http://bloss.msdn.com/b/ericlippert/archive/2007/03/11/lambda-expressions-vs-anonymous-methods-part-five.aspx Lưu ý tất nhiên ví dụ này cho thấy độ phân giải quá tải trong C # ít nhất là NP-HARD. Cho dù đó là NP-HARD hay thực sự không thể giải quyết được phụ thuộc vào một số chi tiết tinh tế nhất định trong cách thức chuyển đổi loại hoạt động với sự hiện diện của chống chỉ định chung, nhưng đó là một chủ đề cho một ngày khác.