無向グラフのツリー幅は、グラフ理論で非常に重要な概念です。小さいツリー幅でグラフを分解すると、高速で実行される多数のグラフアルゴリズムが発明されました。
ツリー幅は、多くの場合、ツリー分解の観点から定義されます。ウィキペディアの好意によるグラフとそのグラフのツリー分解を以下に示します。
ツリー分解とは、各頂点が次のプロパティを持つ元のグラフの頂点のサブセットに関連付けられているツリーです。
- 元のグラフのすべての頂点は、少なくとも1つのサブセットにあります。
- 元のグラフのすべてのエッジには、少なくとも1つのサブセットに両方の頂点があります。
- サブセットに特定の元の頂点が含まれる分解内のすべての頂点が接続されます。
上記の分解がこれらの規則に従っていることを確認できます。ツリー分解の幅は、その最大サブセットのサイズから1を引いたものです。したがって、上記の分解では2です。グラフのツリー幅は、そのグラフのツリー分解の最小幅です。
この課題では、接続された無向グラフが与えられ、そのツリー幅を見つける必要があります。
ツリーの分解を見つけるのは困難ですが、ツリー幅を計算する方法は他にもあります。ウィキペディアのページには詳しい情報がありますが、ツリー幅を計算するためのアルゴリズムでよく使用される、そこに記載されていないツリー幅の計算方法の1つは、最小消去順序幅です。この事実を使用した論文についてはこちらをご覧ください。
消去順序では、グラフのすべての頂点を一度に1つずつ消去します。各頂点が削除されると、その頂点のすべての隣接点を互いに接続するエッジが追加されます。これは、すべての頂点がなくなるまで繰り返されます。削除順序幅は、削除される頂点がこのプロセス中に持つ隣接の最大数です。treewidthは、消去順序幅のすべての順序の最小値に等しくなります。以下に、この事実を使用してツリー幅を計算するプログラムの例を示します。
import itertools
def elimination_width(graph):
max_neighbors = 0
for i in sorted(set(itertools.chain.from_iterable(graph))):
neighbors = set([a for (a, b) in graph if b == i] + [b for (a, b) in graph if a == i])
max_neighbors = max(len(neighbors), max_neighbors)
graph = [edge for edge in graph if i not in edge] + [(a, b) for a in neighbors for b in neighbors if a < b]
return max_neighbors
def treewidth(graph):
vertices = list(set(itertools.chain.from_iterable(graph)))
min_width = len(vertices)
for permutation in itertools.permutations(vertices):
new_graph = [(permutation[vertices.index(a)], permutation[vertices.index(b)]) for (a, b) in graph]
min_width = min(elimination_width(new_graph), min_width)
return min_width
if __name__ == '__main__':
graph = [('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'e'), ('b', 'f'), ('b', 'g'),
('c', 'd'), ('c', 'e'), ('d', 'e'), ('e', 'g'), ('e', 'h'), ('f', 'g'), ('g', 'h')]
print(treewidth(graph))
例:
[(0, 1), (0, 2), (0, 3), (2, 4), (3, 5)]
1
[(0, 1), (0, 2), (1, 2), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (3, 4), (4, 6), (4, 7), (5, 6), (6, 7)]
2
[(0, 1), (0, 3), (1, 2), (1, 4), (2, 5), (3, 4), (3, 6), (4, 5), (4, 7), (5, 8), (6, 7), (7, 8)]
3
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
4
入力としてグラフを受け取り、ツリー幅を出力として返す必要があります。入力形式は柔軟です。入力として、エッジのリスト、隣接マップ、または隣接行列を使用できます。別の入力形式を使用する場合は、コメントを入力してください。入力が接続されていると仮定し、エッジのリストを使用するなどして、入力形式にその仮定を組み込むことができます。
編集:ツリー幅を計算する組み込み操作は許可されていません。これを前もって指定していないことをおaびします。
最短のコードが優先されます。
(V,E)
なので、これは有効な入力でしょうか?