トポロジーソートの総数


11

特定のDAG(有向非巡回グラフ)の場合、そのトポロジーの並べ替えはすべての頂点の順列であり、DAGのすべてのエッジ(u、v)について、uは順列のvの前に表示されます。

あなたのタスクは、特定のDAGのトポロジカルソートの総数を計算することです。

ルール

  • エンコーディングで有用な計算を行わない限り、隣接行列、隣接リスト、エッジリストなど、任意の形式を使用してグラフを表すことができます。有用な場合は、入力に頂点数や頂点リストなどを含めることもできます。
  • 入力のグラフは常にDAGであると想定できます(サイクルはありません)。
  • あなたのプログラムは理論的にはどんな入力に対しても機能するはずです。ただし、言語の基本的な整数型をオーバーフローすると失敗する可能性があります。
  • 頂点の名前は、任意のタイプの任意の連続した値にすることができます。例:0または1から始まる数値(もちろん、この数値にコードを格納していない場合のみ)。
  • これはコードゴルフです。最短のコードが勝ちます。

これは、異なる形式の同じ入力です。プログラムはそれらすべてを受け入れる必要はありません。頂点は常に0から始まる整数です。

Adjacency list:
[ [1 2 3 5] [2 4] [] [2] [] [3] ]
Adjacency matrix:
[ [0 1 1 1 0 1] [0 0 1 0 1 0] [0 0 0 0 0 0] [0 0 1 0 0 0] [0 0 0 0 0 0] [0 0 0 1 0 0] ]
Edge list:
6 [ [0 1] [0 2] [0 3] [0 5] [1 2] [1 4] [3 2] [5 3] ]

これは、この画像に示されているグラフです。

グラフの例

出力は次のようになります。

9

トポロジカルソートは次のとおりです。

[0 1 4 5 3 2]
[0 1 5 4 3 2]
[0 1 5 3 4 2]
[0 1 5 3 2 4]
[0 5 1 4 3 2]
[0 5 1 3 4 2]
[0 5 1 3 2 4]
[0 5 3 1 4 2]
[0 5 3 1 2 4]

関数?プログラム全体?どっち?
isaacg 2015

@isaacgどちらか。
jimmy23013

回答:


4

CJam-25

q~{_f{1$-_j@j@&!*}_!+:+}j

user23013からの大きな助けを借りて:)

オンラインでお試しください

説明:

一般的なアルゴリズムは、xnorのPythonソリューションと同じです。
ここで重要なのは、j再帰をメモする演算子です。パラメータ、初期値の値または配列(f(0)、f(1)など)とブロックを使用して、再帰を定義します。jオペレータは、同じブロックに再帰的(及びメモ化)の呼び出しを行うためのブロック内で再度使用されます。複数のパラメーターで使用することもできますが、ここではそうではありません。
user23013の素晴らしい革新は、初期値の配列として隣接リストを利用して、さまざまなデータ型でjを使用することです。

q~             read and evaluate the input (vertex list followed by adjacency list)
{…}j           run the block on the vertex list, doing memoized recursion
                and using the adjacency list for initial values
    _          copy the vertex list
    f{…}       for each vertex and the vertex list
        1$-    copy the vertex and remove it from the list
                Python: "V-{v}"
        _j     copy the reduced list and call the j block recursively
                this solves the problem for the reduced vertex list
                Python: "f(G,V-{v})"
        @j     bring the vertex to the top of the stack and call the j block recursively
                in this case, it's called with a vertex rather than a list
                and the memoized value is instantly found in the list of initial values
                effectively, this gets the list of vertices adjacent to the current vertex
                Python: "G[v]"
        @&     bring the reduced list to the top of the stack and intersect
        !*     multiply the number of topological sorts of the reduced vertex list
                with 1 if the intersection was empty and 0 if not
                Python: equivalent to "*(V-G[v]==V)"
               after this loop we get an array of sub-results for the reduced vertex lists
    _!+        add 1 or 0 to the array if the array was empty or not
                because we want to get 1 for the empty array
                Python: equivalent to "V<{0}or"
    :+         add the numbers in the array
                Python: "sum(…)"

1
入力で頂点リストを明示的に許可するように編集されました。現在は25バイトです。
jimmy23013 2015

@ user23013これはどんな魔術ですか?:O
SEは悪であるためaditsuは終了

7

Python、58

f=lambda G,V:V<{0}or sum(f(G,V-{v})*(V-G[v]==V)for v in V)

入力は、隣接ディクショナリGと頂点セットで構成されVます。

G = {0:{1,2,3,5}, 1:{2,4}, 2:set(), 3:{2}, 4:set(), 5:{3}, 6:set()}
V = {0,1,2,3,4,5}

コードは再帰的です。セットにVは、訪問する必要があるすべてのノードが格納されます。潜在的な次のノードごとに、残りの頂点がそのノードを指していないかどうかをV-G[v]==V確認しV、それG[v]が互いに素であるかどうかをチェックして、その適切性をチェックします。そのようなすべての適切な頂点について、トポロジーソートの数を追加し、それを削除します。基本ケースとして、空のセットは1を与えます。


エッジリストを使用しない場合は+1。
jimmy23013 2015

5

Mathematica、80 57 51バイト

Count[Permutations@#,l_/;l~Subsets~{2}~SubsetQ~#2]&

定義の非常に簡単な実装。私はすべての順列を生成し、それらの有効数を数えています。順列が有効かどうかを確認するために、順列の頂点のすべてのペアを取得します。便利なことに、Subsets[l,{2}]すべてのペアを提供するだけでなく、それらが見つかった順序も維持しますl-必要なものだけです。

上記は、頂点リストとエッジリストを期待する関数です。

f[{1, 2, 3, 4, 5, 6}, {{1, 2}, {1, 3}, {1, 4}, {1, 6}, {2, 3}, {2, 5}, {4, 3}, {6, 4}}]

関数を呼び出す場合f

私はこれをゴルフしようとするか、多分後で別のアプローチを使うでしょう。


2

Pyth、27バイト

Mlf!sm}_dHfq2lYyTfqSZUZ^UGG

2入力関数を定義しますg。最初の入力は頂点の数、2番目は有向エッジのリストです。

テストする:

Code:
Mlf!sm}_dHfq2lYyTfqSZUZ^UGGghQeQ

Input:
6, [ [0, 1], [0, 2], [0, 3], [0, 5], [1, 2], [1, 4], [3, 2], [5, 3] ]

ここで試してください。


@ user23013のカウントとリストが式で使用されています^UGG。これGにより、のすべてのエントリリストが生成されますrange(len(G))
isaacg 2015

つまり[0, 1, ...]、入力で直接使用する場合は短くなりますか?
jimmy23013 2015

@ user23013いいえ、それは同じ長さになります:^GlG^UGG
isaacg 2015

2

ハスケル、102の 107 100 89 85バイト

import Data.List
(%)=elemIndex
n#l=sum[1|p<-permutations[0..n],and[u%p<v%p|[u,v]<-l]]

入力は最大の頂点番号(0で始まる)とエッジリストで、エッジは2つの要素のリストです。使用例:5 # [[0,1], [0,2], [0,3], [0,5], [1,2], [1,4], [3,2], [5,3]]

仕組み:pすべてのエッジが[u,v]満たす頂点のすべての順列を数えます:uinのp位置がvinの位置よりも小さいp。これは、定義を直接実装したものです。

編集:私の最初のバージョンはトポロジーの並べ替え自体を返しましたが、数はありませんでした。修正しました。

編集II:頂点が接続されていないグラフでは機能しませんでした。修正しました。


頂点だけでエッジはないテストケースを追加することを考えています...
jimmy23013 '19 / 02/19

@ user23013:頂点が接続されていないグラフで機能するようになりました。さらに短くなった。
nimi 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.