2017-10-27 3 views
1

私はBoost BGL C++を使用しています。ソース頂点からターゲット頂点までBFSを行い、すべての一意のパスを返すにはグラフが必要です。ブーストBGL BFSソースからターゲットまでのすべての一意のパスを見つける

今、フィルタリングされたグラフを使用して、ソースからターゲットへのパスを含むグラフのサブセットを取得する方法を考えましたが、フィルタされたグラフにはアクセスされた頂点が含まれていたソースからターゲットへのパスの一部。この情報を得る方法はありますか?それとも別のアプローチが良いですか?参考のため

コード:

boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> Graph::getUniquePathsFromSource(VertexDescr source, VertexDescr target, DirectedGraph const & g) 
{ 
    std::vector<double> distances(num_vertices(g)); 
    std::vector<boost::default_color_type> colormap(num_vertices(g)); 

    // Run BFS and record all distances from the source node 
    breadth_first_search(g, source, 
     visitor(make_bfs_visitor(boost::record_distances(distances.data(), boost::on_tree_edge()))) 
     .color_map(colormap.data()) 
    ); 

    for (auto vd : boost::make_iterator_range(vertices(g))) 
     if (colormap.at(vd) == boost::default_color_type{}) 
      distances.at(vd) = -1; 

    distances[source] = -2; 

    boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> 
     fg(g, {}, [&](VertexDescr vd) { return distances[vd] != -1; }); 

    // Print edge list 
    std::cout << "filtered out-edges:" << std::endl; 
    std::cout << "Source Vertex: " << source << std::endl; 

    auto ei = boost::edges(fg); 

    typedef boost::property_map<DirectedGraph, boost::edge_weight_t>::type WeightMap; 
    WeightMap weights = get(boost::edge_weight, fg); 

    for (auto it = ei.first; it != ei.second; ++it) 
    { 
     if (source != boost::target(*it, g)) { 
      std::cout << "Edge Probability " << *it << ": " << get(weights, *it) << std::endl; 
     } 
    } 

    return fg; 
} 

入力(vertex1、vertex2、体重):

0 1 0.001 
0 2 0.1 
0 3 0.001 
1 5 0.001 
2 3 0.001 
3 4 0.1 
1 482 0.1 
482 635 0.001 
4 705 0.1 
705 5 0.1 
1 1491 0.01 
1 1727 0.01 
1 1765 0.01 

出力(ソース= 0の場合、TARGET = 5):

Source Vertex: 0 
Edge Probability (0,1): 0.001 
Edge Probability (0,2): 0.1 
Edge Probability (0,3): 0.001 
Edge Probability (1,5): 0.001 
Edge Probability (1,482): 0.1 
Edge Probability (1,1491): 0.01 
Edge Probability (1,1727): 0.01 
Edge Probability (1,1765): 0.01 
Edge Probability (2,3): 0.001 
Edge Probability (3,4): 0.1 
Edge Probability (4,705): 0.1 
Edge Probability (482,635): 0.001 
Edge Probability (705,5): 0.1 

期待される出力:

0->1->5 
0->3->4->705->5 
0->2->3->4->705->5 

答えて

1

訪問先ノードを追跡するためにカラーマップを使用するため、BFSアルゴリズムは使用しません。ただし、すべての別々のパスを使用する場合は、すでにアクセスしているノードをスキップしたくない場合があります(代替パスをスキップする可能性があるため)。

代わりに、すべての隣接ノードを単に訪問するブルートフォース幅優先の再帰アルゴリズムを実装します。がすでに現在のパスにない場合を除きます。

必須の状態はすべて現在のパスです。

アイデアは、ここでは詳細に説明されている:https://www.quora.com/How-should-I-find-all-distinct-simple-paths-between-2-given-nodes-in-an-undirected-graph

Live On Coliru

#include <boost/graph/adjacency_list.hpp> 
#include <boost/graph/graph_utility.hpp> // print_graph 
using namespace boost; 
using Graph = adjacency_list<vecS, listS, directedS, property<vertex_index_t, int>, property<edge_weight_t, double> >; 
Graph read_graph(); 

using Vertex = Graph::vertex_descriptor; 
using Path = std::vector<Vertex>; 

template <typename Report> 
void all_paths_helper(Vertex from, Vertex to, Graph const& g, Path& path, Report const& callback) { 
    path.push_back(from); 

    if (from == to) { 
     callback(path); 
    } else { 
     for (auto out : make_iterator_range(out_edges(from, g))) { 
      auto v = target(out, g); 
      if (path.end() == std::find(path.begin(), path.end(), v)) { 
       all_paths_helper(v, to, g, path, callback); 
      } 
     } 
    } 

    path.pop_back(); 
} 

template <typename Report> 
void all_paths(Vertex from, Vertex to, Graph const& g, Report const& callback) { 
    Path state; 
    all_paths_helper(from, to, g, state, callback); 
} 

int main() { 
    auto g = read_graph(); 
    print_graph(g, std::cout); 

    auto by_vertex_id = [&](int id) { 
     return *find_if(vertices(g), [&](Vertex vd) { return id == get(vertex_index, g, vd); }); 
    }; 

    all_paths(by_vertex_id(0), by_vertex_id(5), g, [&](Path const& path) { 
      std::cout << "Found path "; 
      for (auto v : path) 
       std::cout << get(vertex_index, g, v) << " "; 
      std::cout << "\n"; 
     }); 
    std::cout.flush(); 
} 

// immaterial to the task, reading the graph 
Graph read_graph() { 
    std::istringstream iss(R"(
     0 1 0.001 
     0 2 0.1 
     0 3 0.001 
     1 5 0.001 
     2 3 0.001 
     3 4 0.1 
     1 482 0.1 
     482 635 0.001 
     4 705 0.1 
     705 5 0.1 
     1 1491 0.01 
     1 1727 0.01 
     1 1765 0.01)"); 

    Graph g; 
    auto vertex = [&,idx=std::map<int,Vertex>{}](int id) mutable { 
     auto it = idx.find(id); 
     if (it != idx.end()) 
      return it->second; 
     return idx.emplace(id, add_vertex(id, g)).first->second; 
    }; 

    for (std::string line; getline(iss, line);) { 
     std::istringstream ls(line); 
     int s,t; double w; 
     if (ls >> s >> t >> w) { 
      add_edge(vertex(s), vertex(t), w, g); 
     } else { 
      std::cerr << "Skipped invalid line '" << line << "'\n"; 
     } 
    } 

    return g; 
} 

印刷し、どの:答えを

1 --> 5 482 1491 1727 1765 
0 --> 1 2 3 
2 --> 3 
3 --> 4 
5 --> 
4 --> 705 
482 --> 635 
635 --> 
705 --> 5 
1491 --> 
1727 --> 
1765 --> 
Found path 0 1 5 
Found path 0 2 3 4 705 5 
Found path 0 3 4 705 5 
+0

1! は私が 'オートby_vertex_id = [&](int型のID){ リターン*のfind_if(頂点(G)、[&](頂点VD){リターンID ==取得(vertex_index、グラムせずにあなたのソリューションで先に行ってきました、vd);}); }; ' 私が理解しているところでは、これはvertex_indexが頂点ディスクリプタと等しいかどうかをチェックします。 –

+1

ソース/ターゲットの頂点の記述子を見つけるのに何か必要ですか? (純粋なC++ 11)(http://coliru.stacked-crooked.com/a/f6ab72e2f77e7982)または[純粋なC++ 03](http ://coliru.stacked-crooked.com/a/f9f977cb27e000b3)。 C++は本当に長い道のりを歩んできました – sehe

+0

ああ私はラムダ大会には比較的新しいので、私はまだそれを学んでいます。ありがとう! –

関連する問題