2012-01-27 7 views
5

私は、BFSが最短パスを把握するためにキューでどのように動作するのかを理解しようとしています。シンプルなbfsの例...私はそれを得ません

開始点が「9」でターゲットが「0」であるとします。

だから... ...私はスタートを押して...

push 9 {9} 
pop 9 {} 
push 6 {6} 
push 8 {6,8} 
pop 6 {8} 
push 3 {8,3} 
push 5 {8,3,5} 
pop 8 {3,5} 
push 7 {3,5,7} 
pop 3 {5,7} 
push 2 {5,7,2} 
pop 5 {7,2} 
push 4 {7,2,4} 
pop 7 {2,5} 
found 0 

は、どのように私はこの混乱からの最短経路を抽出することができますか?私はこれが私に最短経路を与える方法を見ない。私はそれについて間違っていると思いますか?

ありがとうございます!

答えて

5

最短パスを見つけるために、各ノードはBFS中にどのように到達したかを「覚えておく」必要があります。

例では、map<int,int>を使用できます。
簡単な例:

map[9] = -1; //indicationg source 
map[6] = 9; 
map[8] = 9; 
map[3] = 6; 
map[7] = 8 ; 
... 
map[0] = 7; 

[値のとき-1]だけ0からソースへのパスをたどる、最短経路を取得します。

2

あなたがする必要があることは、ノードごとにどのようにそこに着いたかを覚えておくことです。これは、(ノードを表すために構造体またはクラスを使用している場合)各ノードにデータ・メンバーを追加するか、侵略的ではない整数またはノード・ポインターの並列リストを保持することです。あなたがこれをC++でタグ付けしたので、私はあなたがC++ソリューションを探していると仮定します。

#include <iostream> 
#include <queue> 
#include <stdexcept> 
#include <vector> 

struct graph { 

    graph(size_t nodes) 
    : m_adjacency_list(nodes) { 
    } 

    size_t number_of_nodes() const { 
    return m_adjacency_list.size(); 
    } 

    std::vector<size_t> const& neighbours_of(size_t node) const { 
    return m_adjacency_list.at(node); 
    } 

    void add_edge(size_t from, size_t to) { 
    std::vector<size_t>& al = m_adjacency_list.at(from); 
    if (to >= m_adjacency_list.size()) 
     throw std::runtime_error("Tried to add edge to non-existant node"); 
    for (size_t i = 0; i < al.size(); ++i) if (al[i] == to) return; 
    al.push_back(to); 
    } 

private: 

    std::vector<std::vector<size_t>> m_adjacency_list; 
}; 


int main() { 

    // generate your grid 
    graph g(10); 
    g.add_edge(1, 2); 
    g.add_edge(1, 4); 
    g.add_edge(2, 1); 
    g.add_edge(2, 3); 
    g.add_edge(2, 5); 
    g.add_edge(3, 2); 
    g.add_edge(3, 6); 
    g.add_edge(4, 1); 
    g.add_edge(4, 5); 
    g.add_edge(4, 7); 
    g.add_edge(5, 2); 
    g.add_edge(5, 4); 
    g.add_edge(5, 6); 
    g.add_edge(5, 8); 
    g.add_edge(6, 3); 
    g.add_edge(6, 5); 
    g.add_edge(6, 9); 
    g.add_edge(7, 4); 
    g.add_edge(7, 8); 
    g.add_edge(7, 0); 
    g.add_edge(8, 5); 
    g.add_edge(8, 7); 
    g.add_edge(8, 9); 
    g.add_edge(9, 6); 
    g.add_edge(9, 8); 
    g.add_edge(0, 7); 

    // do the bfs 
    std::vector<size_t> reached_by(g.number_of_nodes(), g.number_of_nodes()); 
    std::queue<size_t> q; 
    size_t start = 9; 
    size_t target = 0; 
    reached_by[start] = start; 
    q.push(start); 
    while (!q.empty()) { 
    size_t node = q.front(); 
    q.pop(); 
    for (size_t i = 0; i < g.neighbours_of(node).size(); ++i) { 
     size_t candidate = g.neighbours_of(node)[i]; 
     if (reached_by[candidate] == g.number_of_nodes()) { 
     reached_by[candidate] = node; 
     if (candidate == target) break; 
     q.push(candidate); 
     } 
    } 
    } 

    if (reached_by[target] == g.number_of_nodes()) 
    std::cout<<"No path to "<<target<<" found!"<<std::endl; 
    else { 
    std::cout<<"Path to "<<target<<": "; 
    for (size_t node = target; node != start; node = reached_by[node]) 
     std::cout<<node<<" <- "; 
    std::cout<<start<<std::endl; 
    } 

} 

このコードでは、ベクターreach_byを使用して、どのノードからどのノードに到達したかを追跡しています。ターゲットが見つかると、そのベクトルを使って出発点に向かって逆方向にトレースすることができます。

このプログラムを実行しているの出力は

Path to 0: 0 <- 7 <- 8 <- 9 
+0

あなたは既に訪問されたノードをマークするために、追加のマーク[]フラグ配列を持っている必要がありますか?私のローカルマシンで実行されると、あなたの実装は無期限にループするようです。 – evandrix

関連する問題