手算的話狀態太多了,估計會算崩潰。。。
程序的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