手算的话状态太多了,估计会算崩溃。。。
程序的idea很简单,枚举+动态规划,每次找两个还不确定大小关系的数比较,然后算两个分支各自还需要多少步,取较大的那个。难点就在于状态的判重。对于每个状态,先求出大小关系的transitive closure,然后10个点的DAG最多有45条边,用一个long long的bitmask就可以表示。但是2^45的state space显然不能接受,所以要判重。DAG的graph isomorphism是NP hard的,所以没有什么好办法hashing。一种办法是求DAG的最小表示,也就是考虑所有可能的topological order,算出所有这些order下最小的那个bitmask,作为该DAG所对应的数。最坏情况下要枚举接近10!种order,所以会非常慢。一个改进的办法是对于每个弱连通分支分别求最小表示,然后排序后连起来。总之,在扩展了接近2,500,000个unique state之后,算出来是22。我的程序加了很多优化,在一般的机器上不到半个小时可以跑出来。
我也写了另一种基于剪枝的算法,就是算出当前的关系下valid的topological order的数目x,然后用log_2(x)作为一个lower bound来剪枝。这样做会出现一些其它问题,程序跑起来也没快多少,不过扩展的states少了,有大约1,000,000个。
如果要算n=11的话这个程序应该也没问题,找一台内存大一点的机器跑个一两天应该能出解。如果n再大的话,就需要更好的算法和更好的剪枝了。
下面把第一种算法的程序贴出来,有兴趣的话不妨去运行一下。不过可惜程序写得很乱,也没加注释,可读性很差。
#include
#include
#include
#include
#include
idiot94
2009-08-21 07:55:36NIU!!!