グラフ検索とツリー検索 DFSのバージョンの違いは何ですか、A *は人工知能で検索しますか?
既存の答えから判断すると、この概念については多くの混乱があるようです。
ツリー検索とグラフ検索の区別は、問題のグラフがツリーであるか一般的なグラフであるかという事実に根ざしていません。一般的なグラフを扱っていると常に仮定されています。区別はtraversal patternにあります。これは、グラフを検索するために使用され、グラフ型またはツリー型の場合があります。
ツリー型のproblemを扱っている場合、両方のアルゴリズムのバリアントは同等の結果につながります。そのため、より単純なツリー検索バリアントを選択できます。
基本的なグラフ検索アルゴリズムは次のようになります。開始ノードstart
を使用して、ループ条件で使用されるsuccessors
およびgoal
の指定としてエッジを向けます。 open
はメモリ内のノードを保持します。これは現在検討中です、open list。次の擬似コードは、すべての面で正しいわけではないことに注意してください(2)。
open <- []
next <- start
while next is not goal {
add all successors of next to open
next <- select one node from open
remove next from open
}
return next
実装方法によってselect from open
、深さ優先検索(DFS)(最新の要素を選択)、幅優先検索(BFS)(最も古い要素を選択)、または均一コスト検索(パスコストが最も低い要素を選択)などの検索アルゴリズムのさまざまなバリエーションを取得します。最も低いcost plus heuristic値などのノードを選択することによる、人気のあるAスター検索。
上記のアルゴリズムは、実際にはtree searchと呼ばれます。開始状態をルートとする複数の有向パスがある場合、基礎となる問題グラフの状態に複数回アクセスします。有向ループ上にある場合、状態を無限に訪れることさえ可能です。ただし、各訪問は、検索アルゴリズムによって生成されたツリー内の異なるnodeに対応します。後で説明するように、この明らかな非効率性が望まれる場合があります。
見てきたように、ツリー検索は状態を複数回訪問できます。そのため、この状態の後に見つかった「サブツリー」を数回探索しますが、これは高価になる可能性があります。グラフ検索は、closed listですべての訪問済み状態を追跡することでこれを修正します。 next
の新たに見つかった後継者が既にわかっている場合は、オープンリストに挿入されません。
open <- []
closed <- []
next <- start
while next is not goal {
add next to closed
add all successors of next to open, which are not in closed
remove next from open
next <- select from open
}
return next
グラフ検索では、訪問したすべての状態を追跡するため、より多くのメモリが必要であることがわかります。これは、小さなオープンリストによって補われる場合があり、検索効率が向上します。
select
を実装するいくつかの方法は、最適なソリューションを返すことを保証できます。つまり、shortestパスまたはminimalコストのパス(コストがエッジに付加されたグラフの場合)。これは、コストが増加する順にノードが展開されるとき、またはコストがゼロ以外の正の定数であるときに基本的に成り立ちます。この種の選択を実装する一般的なアルゴリズムは、 均一コスト検索 、またはステップコストが同一の場合、 [〜#〜] bfs [〜#〜] または [〜#〜] iddfs [〜#〜] 。 IDDFSは、BFSの積極的なメモリ消費を回避し、ステップサイズが一定の場合、一般的に情報のない検索(ブルートフォース)に推奨されます。
(非常に一般的な)A *tree検索アルゴリズムは、 admissible heuristic 。ただし、A *graph検索アルゴリズムは、 consistent(または "単調」)ヒューリスティック (許容性よりも強い条件)。
簡単にするために、提示されたコードは以下を行いません。
ツリーはグラフの特殊なケースであるため、一般的なグラフで機能するものはすべてツリーで機能します。ツリーは、ノードの各ペア間に正確に1つのパスがあるグラフです。これは、以前の回答が示すように、サイクルを含まないことを意味しますが、サイクルのない有向グラフ(DAG、有向非巡回グラフ)は必ずしもツリーではありません。
ただし、グラフにいくつかの制限があることがわかっている場合、たとえばツリーまたはDAGである場合、通常、無制限のグラフよりも効率的な検索アルゴリズムを見つけることができます。たとえば、A *またはその非ヒューリスティックな対応の「ダイクストラのアルゴリズム」をツリー(DFSまたはBFSで検索できるパスが1つだけ選択される)で使用することは、おそらくあまり意味がありません。 DAG(トポロジカルソートによって取得された順序で頂点を考慮することにより最適なパスを見つけることができる場所)。
有向対無向に関しては、無向グラフは有向グラフの特殊なケースです。つまり、「からへのエッジ(リンク、遷移)がある場合」 vvからまでのEdgeもあります。
更新:グラフ自体の構造ではなく検索の横断パターンが重要な場合、これは答えではないことに注意してください。たとえば、@ ziggystarの回答を参照してください。
グラフとツリーの唯一の違いはcycleです。グラフにはサイクルを含めることができますが、ツリーにはできません。したがって、ツリーに検索アルゴリズムを実装する場合、サイクルの存在を考慮する必要はありませんが、任意のグラフで作業する場合は、それらを考慮する必要があります。サイクルを処理しないと、アルゴリズムは最終的に無限ループまたは無限再帰に陥る可能性があります。
考えるべきもう1つのポイントは、扱っているグラフの方向性のプロパティです。ほとんどの場合、各エッジでの親子関係を表すツリーを扱います。 DAG(有向非巡回グラフ)も同様の特性を示します。ただし、双方向グラフは異なります。双方向グラフの各エッジは、2つの近傍を表します。したがって、これらの2種類のグラフでは、アルゴリズムのアプローチが少し異なります。
簡単な言葉で言えば、ツリーにはサイクルが含まれておらず、グラフが可能な場所です。したがって、検索を行うときは、無限ループに陥らないようにグラフのサイクルを回避する必要があります。
別の側面として、ツリーには通常、ある種のトポロジカルソートまたはバイナリ検索ツリーのようなプロパティがあり、グラフに比べて検索が非常に高速で簡単になります。
グラフとツリー
ただし、AIグラフ検索とツリー検索の場合
グラフ検索には、アルゴリズムが新しいノードを探索し、「使用したアルゴリズムに関係なく」訪問済みとマークするたびに、通常、現在のノードから到達可能な他のすべてのノードを探索する優れた特性があります。
たとえば、3つの頂点A BおよびCを持つ次のグラフを検討し、次のエッジを検討します
A-B、B-C、およびC-A、CからAへのサイクルがあります。
また、Aから始まるDFSを実行すると、Aは新しい状態Bを生成し、Bは新しい状態Cを生成しますが、Cを探索すると、アルゴリズムは新しい状態Aを生成しようとしますが、Aは既にアクセスされているため、無視されます。クール!
しかし、木はどうですか?よく木アルゴリズムは、訪問済みノードを訪問済みとしてマークしませんが、ツリーにはサイクルがありません、無限ループでどのように取得しますか?
3つの頂点を持つこのツリーを検討し、次のエッジを検討します
A-B-CはAをルートとし、下向きです。そして、DFSアルゴリズムを使用していると仮定しましょう
Aは新しい状態Bを生成し、Bは2つの状態AとCを生成します。これは、ツリーに「探索されたノードをマーク」がないため、DFSアルゴリズムが再びAを探索し、新しい状態Bを生成するためです。無限ループに陥っています。
しかし、何か気づいたことがありますか?もちろん、これはサイクルではありません。サイクルは頂点が3以上でなければならず、最初と最後のノードを除くすべての頂点が異なることを意味するためです。
ST A-> B-> A-> B-> Aサイクル特性に違反しているため、サイクルではありません> =3。しかし実際にA-> B-> C-> Aはサイクル> = 3個の異なるノードがチェックされています。最初と最後のノードは同じです。
再度、A-> B-> C-> B-> Aのツリーエッジを考えてみましょう。もちろん2つのBがあり、すべてのノードが異なるわけではないため、サイクルではありません。
最後に、ツリー検索アルゴリズムを実装して、同じノードを2回探索しないようにすることができます。しかし、それは結果をもたらします。