これは、以前の質問Solve a simplepackcombination with dependenciesに基づいていますが、これを理解するためにその質問をチェックアウトする必要はありません。
この質問は、部分的に順序付けられたセットの線形拡張の数を数える最速の方法について尋ねます。
このような部分的に順序付けられたリストは、オブジェクトの任意の順序が与えられた場合のパッキング構成の実現可能性として視覚化できます。質問は、配置されたブロックを移動できない場合、示されているパッキング構成を実現するために、渡されたすべてのブロックの可能な順序は何ですか?
この例では、すべてのブロック ABCDEFG を配置する必要があります。A、B、C、D の依存関係: set{}、E: set{A,B}、F: set{B,C} G: set{C、 D}。
7 つのブロックのすべての順列をチェックし、依存関係を満たす数を数えることで、部分的に順序付けられたセットを完成させる可能性をすべて得ることができます。以前の投稿の גלעד ברקן によって、より高速な代替手段が提供されました。彼は、既に探索されたノードで依存関係が満たされない場合、ブランチへのさらなる探索を終了するグラフ構造を使用しました。
nodes = {
'A': {
'neighbours': ['B','C','D','E','F','G'], 'dependency': set()},
'B': {
'neighbours': ['A','C','D','E','F','G'], 'dependency': set()},
'C': {
'neighbours': ['A','B','D','E','F','G'], 'dependency': set()},
'D': {
'neighbours': ['A','B','C','E','F','G'], 'dependency': set()},
'E': {
'neighbours': ['C','D','F','G'], 'dependency': set(['A','B'])},
'F': {
'neighbours': ['A','D','E','G'], 'dependency': set(['B','C'])},
'G': {
'neighbours': ['A','D','E','G'], 'dependency': set(['C','D'])},
}
def f(key, visited):
if len(visited) + 1 == len(nodes):
return 1
if nodes[key]['dependency'] and not nodes[key]['dependency'].issubset(visited):
return 0
result = 0
for neighbour in nodes[key]['neighbours']:
if neighbour not in visited:
_visited = visited.copy()
_visited.add(key)
result += f(neighbour, _visited)
return result
print 2 * f('A', set()) + 2 * f('B', set()) # exploiting symmetry
私の質問は、一般性を失うことなく גלעד ברקן のアルゴリズムをさらに最適化する方法があるかどうかということです。依存関係が少なく、リストを独立したサブリストにさらに分割できる場合は、おそらく高速化できますが、この特定の例ではそうではありません。