質問で使用されている言語をブール式に変換すると、次のようになります。
「A は B に依存する」 => 「(a と b) または (a ではない)」
と
「B は A と衝突する」 => 「(b であり、a ではない) または (b ではない)」
したがって、これを (Python 3 で) 記述する簡単な方法は、デカルト積を生成し (すべての可能な選択肢を与える)、制約が満たされるケースのみを選択することです。簡単にするために、入力に文字の代わりにインデックスを使用しているため、 などy[0]
と同等A
です。ただし、出力を文字に変換しました。
n ノードの場合、このアプローチは 2^n のすべての可能なケースを生成してテストします。より複雑だが潜在的に効率的なアプローチについては、以下を参照してください。
import itertools
bbb = (True,False)
def resolve(n,test):
return [x for x in itertools.product(bbb,repeat=n) if test(x)]
def dependsOn(a,b):
return (a and b) or (not a)
def conflictsWith(b,a):
return (b and not a) or (not b)
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def pr(d):
for dd in d:
s = [letters[i] for i in range(len(dd)) if dd[i] ]
if (len(s) > 0):
print(s,end = " ")
print()
pr(list(resolve(2,lambda y:
dependsOn(y[0],y[1]) and
conflictsWith(y[1],y[0])
)))
pr(list(resolve(2,lambda y:
dependsOn(y[0],y[1]) and
dependsOn(y[1],y[0])
)))
pr(list(resolve(4,lambda y:
dependsOn(y[0],y[1]) and
dependsOn(y[0],y[3]) and
dependsOn(y[1],y[2]) and
conflictsWith(y[3],y[1]) and
conflictsWith(y[3],y[2])
)))
pr(list(resolve(4,lambda y:
conflictsWith(y[0],y[1]) and
conflictsWith(y[1],y[2]) and
conflictsWith(y[2],y[3]) and
conflictsWith(y[3],y[0])
)))
これにより、次の結果が得られます。
['B']
['A', 'B']
['B', 'C'] ['C'] ['D']
['A', 'C'] ['A'] ['B', 'D'] ['B'] ['C'] ['D']
... 4 つのテスト ケースの場合。
詳細については、Wikipedia の真理値表のエントリを参照してください。
(編集)
多くのノードと多くの制約がある問題に対するより効率的なアプローチは、ノードのリストを徐々に構築し、その部分リストが制約に準拠している場合にのみ、各部分リストから構築を続けることです。遠い。resolve
上記の関数を次のバージョンに置き換え、dependsOn
およびconflictsWith
関数を一致するように置き換えることで、これを行うことができます。
import queue
# The following constraint functions return True if the constraint is met
# or if one or more of the elements relating to the constraint is None
def dependsOn(a,b):
if (a != None) and (b != None):
return (a and b) or (not a)
else:
return True
def conflictsWith(b,a):
if (a != None) and (b != None):
return (b and not a) or (not b)
else:
return True
def resolve(n,test):
result = []
testCount = 0
# initialise the list with all None
lst = [None] * n
q = queue.Queue()
q.put(lst)
while not q.empty():
lst = list(q.get())
testCount += 1
if test(lst):
# the list complies with the constraints, at least
# as far as it is populated
if lst[-1] != None:
# we have a fully-populated list
result.append(lst)
else:
i = lst.index(None)
lst[i] = True
q.put(list(lst))
lst[i] = False
q.put(list(lst))
print ("testCount = %d" % testCount)
return result
これにより、4 つのテスト ケースで同じ結果が得られます。ただし、3 番目と 4 番目のテスト ケースでは、 の値はtestCount
それぞれ 21 と 23 です。これは、デカルト積ソリューションに必要なテストの総数 (n=4 の場合は 16) を超えていますが、さらに多くのノードと多くの制約がある場合、このアプローチでは、テストできないノードのサブセットをテストすることを回避できます。には解が含まれている可能性があるため、デカルト積の解よりもはるかに少ないテストで済みます。もちろん、制約がほとんどまたはまったくない最悪のシナリオでは、このアプローチでは最大 2^(n+1) - 1 回のテストが必要になる可能性があります。実際、これは最初の 2 つのテスト ケース (testCount
このアルゴリズムを使用した場合は 7) で発生します。
ここに示されている実装は粗雑であり、確実に速度を最適化できることに注意してください。