C#
您的任务是为SAT编写一个似乎在多项式时间内执行的程序。
“出现”是不必要的。我可以编写一个确实在多项式时间内执行的程序来解决SAT问题。实际上,这非常简单。
超级奖金:如果编写一个实际上在多项式时间内执行的SAT求解器,您将获得一百万美元!但无论如何,请使用扰流器标签,以便其他人对此感到疑惑。
太棒了 请寄给我一百万美元。认真地说,我这里有一个程序,可以用多项式运行时求解SAT。
首先,我要说明我要解决的SAT问题。我将演示如何编写一个展示任何3-SAT问题的独特解决方案的程序。每个布尔变量的值对于我的求解器来说必须是唯一的。
我们首先声明一些简单的辅助方法和类型:
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) { }
现在让我们选择一个3-SAT问题来解决。比方说
(!x3) &
(!x1) &
(x1 | x2 | x1) &
(x2 | x3 | x2)
让我们再加上一点括号。
(!x3) & (
(!x1) & (
(x1 | x2 | x1) &
(x2 | x3 | x2)))
我们这样编码:
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))))))));
}
可以肯定的是,当我们运行该程序时,我们在多项式时间内获得了3-SAT的解决方案。实际上,运行时间是问题大小的线性函数!
x1: false
x2: true
x3: false
您说的是多项式运行时。您没有提到多项式编译时间。该程序强制C#编译器尝试x1,x2和x3的所有可能的类型组合,并选择不显示任何类型错误的唯一组合。编译器完成所有工作,因此运行时不必这样做。我首先在2007年的博客上展示了这种有趣的技术:http : //blogs.msdn.com/b/ericlippert/archive/2007/03/28/lambda-expressions-vs-anonymous-methods-part-five.aspx注意当然,该示例表明C#中的重载分辨率至少为NP-HARD。是NP-HARD还是不确定 在泛型协变存在的情况下,类型可转换如何工作取决于某些细微的细节,但这是另一回事。