2016-11-29 15 views
0

DFAから言語を抽出するアルゴリズムを見つけようとしています。その言語が無限であれば、最大で報告する必要があります:maxcount < = 1000文字列。報告される順序に制限はありません。DFAから言語を抽出するアルゴリズム

私が試してみました:再帰アルゴリズム

(私はちょうど私が何をしたか言葉で説明してアルゴリズムを記述する方法がわからない) - 各遷移のための1つの状態から次の状態/状態に保存遷移が受け入れられた状態にあった場合には、それぞれの遷移に対して再帰的な呼び出しを行い、その後、「行き止まり」に達した場合には、再帰的に注意を喚起する。遷移文字をstate 2state 3'a''b'それぞれ:

は、開始状態がstate 1であるとする2つの遷移があるとします。次に、state 3からstate 4への遷移があり、遷移文字は'c'であり、state 4のみが受け入れ状態です。

state 1からstate 2に行くことは、遷移文字として'a'保存与えるだろうが、state 2は行き止まりであるために再帰的にそこを指摘され、それが受理状態ではないので、レポートにそこを指摘されます。 'b'を保存し、再帰が終了する任意のトランジションを持っていないので、我々は"bc"の合計を持っていることとstate 4以来'c'が保存されますstate 3state 4から行きますstate 1state 3から行く

。そのループ内で「スタック」を取得しないために、「場合」は、別の可能な遷移があることを確認してきた私 - 私はループでDFAをお持ちの場合は受理状態


ある"bc"state 4ので、私たちは報告します我々はいつも遷移を選択し、我々はその状態でどの場所に遷移したかについての最後の時間/時間を推測することはしない。

このアルゴリズムは小さなDFAで機能するが、大きなDFAのスタックオーバーフロー:state 1からstate 2への20の移行とstate 2からへの30の移行を想像してくださいなど)。

もっと効率的なアルゴリズムをお勧めしますか?

+0

は、あなたが任意のグラフアルゴリズムに精通していますか?グラフ検索/接続algoはここで便利です。 – djechlin

+0

アルゴリズムは次のようなものですか?DFAの開始状態と受け入れ状態の間のすべてのパスを見つけるか? –

+0

@djechlin私はそうではありませんが、私が幸せになるような特定のアルゴリズムについて詳しく説明できれば、 –

答えて

0

ノート:この問題は、開始状態とすべての受け入れ状態の間のすべてのパスを見つけるものとしてモデル化できると推測しています。だから、私はこれがグラフの深さ優先検索で達成できると信じています。深さ優先探索は、2つのノード間のすべての非周期的経路を見つける。

Depth First Search (DFS)アルゴリズムに精通している場合は、グラフ検索/トラバーサルアルゴリズムが問題に役立つことがあります。私はあなたに非常に簡単な例を与えます。

与えられた 's'から 'd'までのすべてのパスを出力する、有向グラフ、ソース頂点sとデスティネーション頂点 'd'を指定します。次の有向グラフを考えてみましょう。 sを2、dを3とする.2から3の4つの異なるパスがある。

enter image description here

アイデアは、与えられた有向グラフのDepth First Traversalを行うことです。ソースからトラバーサルを開始します。訪問された頂点を配列path[]などの配列に保存し続けます。送り先の頂点に到達した場合は、path[]の内容を出力します。 重要なことは、現在の頂点を訪問したときにもpath[]にマークすることです。そのため、トラバーサルは1サイクルには入りません。

サンプルコード:あなたは、グラフ内の2つのノード間のすべてのパスを見つけるために、Javahereに非常に単純なコードを見つけることができます。

+0

典型的なDFAでは、状態反復を伴わない文集合の中では、1000よりはるかに小さくなる可能性が高いので、このアルゴリズムが問題の制約を満たすのに十分な文字列を返すことは考えにくい。 – rici

+0

私はあなたの意見を得ていませんでした。あなたは、グラフの2つのノード間のパスを見つけることによってDFSが文法規則を生成できないと言っていますか? –

+0

私は、DFAで一致した文を生成する方法はわかりますが、DFAを通過するトラバースをどのように使って文法を生成するかはわかりません。私がdjechlinに言ったように、なぜあなたのサイクルに受け入れ国が含まれていると信じていますか? (単純なexanple:正規表現 'ab * a'に対応するDFA) – rici

1
  1. サイクル検出アルゴリズムを実行します。
  2. サイクルがない場合は、パスの検索アルゴリズム(BFS、DFS、Dijkstra、A *など)を実行して、開始から終了までのすべてのパスをリストします。
  3. 開始ノードからサイクルまでのパスを見つけるためのパス検索を実行するサイクルがある場合。 N = 1,2,3、...、1000の場合、出力(サイクルに開始ノード)+(接続ノードで始まるサイクル)* N。

代わり:

  1. 変換正規表現します。
  2. 正規表現から単語を生成します。
+0

なぜあなたはサイクルを心配する必要がありますか? 1つの可能な答えは、「サイクルがあるとDFSが決して終了しないため」ですが、DFSはツリーをスキンする唯一の方法ではありません。 – rici

+0

@riciこの質問には多くの回答があります。鉱山は簡単にgoogle可能なコンポーネントになります。 – djechlin

+0

Googleは「あなたが見つけたサイクルに受け入れ可能な状態がない場合はどうすればよいですか? :-)もちろん、アルゴリズムを修正するのは合理的に単純ですが、それほどきれいではありません。 – rici

1

これは、DFAで幅優先検索を行うと、長さで並べ替えられた文字列が生成されます。

状態と文字列で構成されたオブジェクトを定義します(ここではメモリ効率の高いソリューションがありますが、1000文字列を作成するだけであれば問題ありません)。そのようなオブジェクトの作業キューを作成します。状態が開始状態で、文字列が空である単一のオブジェクトでワークキューを初期化します。

あなたがmaxcount文字列またはキューが空になるまで発見した今、次の3つの手順を繰り返します。

  1. をキュー内の最初のオブジェクトを削除します。

  2. 状態が受け入れ可能な状態の場合は、その文字列を出力します。

  3. 可能な各遷移(文字と新しい状態で構成されています)については、トランジションの状態とオブジェクトの文字列とトランジションの文字を連結した新しいオブジェクトをキューの末尾に追加します。

+0

ここで文字列をどういう意味ですか? opはDFAグラフをたどって文法規則を構成したいと考えています。あなたはそれを意味しましたか? –

+0

@wasi:私はそれがOPの構築を望んでいるとは思わない。単語の文字列は質問からまっすぐに来ます(通常、 "文字列"と "文字"ではなく "文"と "トークン"と言うでしょうが、アルゴリズムは同じです)。 – rici

1

BFSを使用する場合、サイクルは関係ありません。アイデアは、現在の状態と先行ノードへのポインタを含む検索ノードを定義することです。したがって、受け入れ状態のノードにアクセスしたときに、前のポインタを逆方向にトレースして、受け入れられた文字列を逆順に判定することができます。検索ノードに前のノードの状態から現在のノードへの遷移を引き起こした文字も含まれているならば、エレガントであることが分かります。

ここでは、Javaのアプローチがあります:

import java.util.ArrayDeque; 
import java.util.ArrayList; 
import java.util.Deque; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 

class Experimental { 
    // DFA state with its transitions, possibly accepting. 
    static class State { 
    final Map<Character, State> transitions = new HashMap<>(); 
    final boolean accept;  
    State(boolean accept) { 
     this.accept = accept; 
    } 
    } 

    // A little DFA. 
    static final State s0 = new State(false); 
    static final State s1 = new State(false); 
    static final State s2 = new State(true); 
    static final State s3 = new State(true); 
    static { 
    s0.transitions.put('a', s1); 
    s0.transitions.put('b', s2); 
    s0.transitions.put('c', s3); 
    s1.transitions.put('d', s3); 
    s2.transitions.put('e', s0); 
    s2.transitions.put('f', s1); 
    } 

    // An enumerator of strings accepted by the DFA in order of length. 
    static class Enumerator { 
    static class Node { 
     final Node prev; 
     final char prevCh; 
     final State state; 
     Node(State start) { 
     this(null, Character.MIN_VALUE, start); 
     } 
     Node(Node prev, char ch, State state) { 
     this.prev = prev; 
     this.prevCh = ch; 
     this.state = state; 
     } 
    } 

    final Deque<Node> queue = new ArrayDeque<>(); 
    final List<String> output = new ArrayList<>(); 
    final State start; 

    Enumerator(State start) { 
     this.start = start; 
    } 

    Enumerator enumerate(int outputLimit) { 
     queue.clear(); 
     output.clear(); 
     // Enqueue a search node for the start state. 
     queue.add(new Node(start)); 
     while (!queue.isEmpty() && output.size() < outputLimit) { 
     Node current = queue.pollFirst(); 
     if (current.state.accept) { 
      // Follow prev pointers to build the accepted string. 
      StringBuilder sb = new StringBuilder(); 
      for (Node p = current; p.prev != null; p = p.prev) { 
      sb.append(p.prevCh); 
      } 
      output.add(sb.reverse().toString()); 
     } 
     // Enqueue nodes for the successors of current state. 
     for (Entry<Character, State> transition : current.state.transitions.entrySet()) { 
      queue.addLast(new Node(current, transition.getKey(), transition.getValue())); 
     } 
     } 
     return this; 
    } 
    } 

    public static void main(String[] args) { 
    System.out.println(new Enumerator(s0).enumerate(20).output); 
    } 
} 

出力:

[b, c, ad, beb, bec, bfd, bead, bebeb, bebec, bebfd, bebead, bebebeb, bebebec, bebebfd, bebebead, bebebebeb, bebebebec, bebebebfd, bebebebead, bebebebebeb] 
関連する問題