使用列入黑名单的边提升过滤图
Posted
技术标签:
【中文标题】使用列入黑名单的边提升过滤图【英文标题】:Boost filtered graph with blacklisted edges 【发布时间】:2017-08-07 20:02:22 【问题描述】:我想在边缘被列入黑名单的图上运行 Dijkstra,即,我想计算不使用这些链接的最短路径。 目前,我首先定义过滤器:
typedef std::pair<int, int> Edge;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_weight_t, int> > graph_t;
结构 BlackListEdgeConstraint 私人的: 标准::设置黑名单; graph_t* g;
public:
BlackListEdgeConstraint():blackList(std::set<Edge>() ),g(NULL);
BlackListEdgeConstraint(std::set<Edge>& list, graph_t* g_) : blackList(list), g(g_)
/**
* This is the "predicate function" used by boost::filtered_graph (
* see http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/filtered_graph.html )
* It it returns true, the edge is included in the filtered graph, otherwise it is excluded.
*/
bool operator()(const boost::graph_traits<graph_t>::edge_descriptor& e) const
Edge edge(source(e,*g), target(e,*g) );
//Include the edge if it's not in the blacklist.
return blackList.find( edge ) == blackList.end();
;
然后我在 5 月执行此操作 main(...)
函数
... I fill the graph g ...
std::set<Edge> blacklist; blacklist.insert( Edge(0,1) );
BlackListEdgeConstraint filter(blacklist, &g);
boost::filtered_graph<graph_t, BlackListEdgeConstraint> filtered(g, filter);
... I run Dikjstra on the filtered graph ...
现在,我所做的工作有效,但很奇怪。实际上,我首先在顶点 0 和 1 之间创建了一条边。然后,在 operator() (...)
内部,我有一个 edge_descriptor
而不是 Edge
(如果我将 Edge 作为参数,编译器会按照 here 的解释进行抱怨,所以我猜boost
正在某处进行一些转换,原因我不知道)。然后,我再次检索operator() (...)
中的顶点 0 和 1,并重建 Edge
。您知道,如果直接接受 operator()(..)
Edge
,我会花很长时间做一些简单的事情。
你认为我可以以更优雅、更高效的方式完成相同的操作吗?
【问题讨论】:
【参考方案1】:你基本上问什么与提升图关系不大。您希望能够高效地查找一对顶点描述符。
决定因素将是黑名单数据结构的选择。
附带说明,您不将
Edge
对象插入到图表中。您选择的图模型是一个邻接列表,因此它存储每个顶点的相邻顶点列表。
pair<int,int>
只是一种方便的类型,用于轻松初始化图形。你完全可以不用它。
在考虑了可能的选择之后,我认为没有更快的方法。
在某些较大的规模上,您可能会获得更高的有效性能
使用本身表示为邻接列表的黑名单(例如std::map<source_vertex, std::list<target_vertex> >
)或
使用unordered_set<>
。
除非大规模进行,否则这两种优化都不太可能产生显着差异。
通过使用boost::container::flat_set
,您可能会受益于参考位置
成本真实吗?
如果您认为“构造 Edge
”是一种资源浪费,请忘记这一点:它是一种 POD 类型 (std::pair<int, int>
),因此只有微不足道的构造函数/析构函数。看到set<Edge>
是一个模板类,对它的大部分操作都可以内联。编译器将内联方法调用、注册参数、删除多余的加载/存储周期并有效地生成最佳代码:
#include <set>
#include <utility>
using Edge = std::pair<int, int>;
using Blacklist = std::set<Edge>;
struct Pred
Blacklist blacklist
92, 29 ,
74, 92 ,
86, 6 ,
67, 35 ,
59, 4 ,
66, 13 ,
82, 37 ,
51, 94 ,
32, 6
;
bool operator()(int source, int target) const
return blacklist.end() != blacklist.find(Edge source, target);
;
View Disassembly Live On Godbolt GCC Explorer
专业提示:点击 Clang 反汇编上的
#
按钮查看优化器 cmets
总结 Edge
类型的成本不存在。任何实际成本都取决于在edge_descriptor
上使用boost::source()
和boost::target()
。
看到您的边缘容器选择器是listS
,您的边缘容器是基于节点的,这意味着边缘描述符是稳定的,并且基本上是对边缘对象的类型擦除引用。调用boost::source(e, g)
只不过是转换描述符和取消引用而已。根据它的使用方式,编译器可能甚至能够看穿这些间接。
如果您不喜欢该成本,请调整 Graph 类型 :)(您的用例可能需要使用 EdgeList 概念,或者受益于使用基于节点的边缘容器等)。
【讨论】:
以上是关于使用列入黑名单的边提升过滤图的主要内容,如果未能解决你的问题,请参考以下文章
javascript 允许在Adblock Plus中将特定频道列入白名单,方法是在URL中添加频道名称,并构建过滤器以添加自定义过滤器
在express,node.js中使用req.ip将IP地址列入白名单是不是安全?
仅因为AI 图像识别技术先进,这些企业就被美国列入"黑名单"?