1 为了能重用已有DijkstraSearcher的一些函数,添加一个类DirectedGraph继承自IGraph,重写虚函数。DirectedGraph中有Node类和Edge类。Node类需要std::vector<unsigned>aedge_ids字段,Edge类需要unsigned snode_id;
unsigned enode_id;
unsigned direction : 2;
unsigned weight : 30;
2 传统Dijkstra在reach一个点时,如果该点是第一次遇到,则将其加入open队列,如果不是第一次遇到,则看是否能更新最短路径。
修改后的Dijkstra在reach一个点时,如果是第一次遇到,也是将其加入open队列:
如果不是第一次遇到,也跟第一次遇到一样,new一个ReachedNode,将其加入open队列。
传统Dijkstra代码里用一个hash_map<unsigned, ReachedNode*> ReachedNodes来存储所有reached的点,是为了能快速的通过nodeid得到reachednode结构,作用有两点:(1)能知道该nodeid现在的路径是多少,便于在第二次reach该点时判断是否需要更新路径长度(2)程序结束时能回溯出最短路径。
全路径搜索里,对每个node会有多个reachednode,它们里面存储的路径长度,parent信息不同,因此需要一个hash_map<unsigned, std::vector<ReachedNode*>> ReachedNodes 来存储。
3为了控制搜索范围,用一个计数器conter来限制每个node被settle的次数。用一个hashmap<unsigned,unsigned>来存储每个点对应的settle次数,如果次数等于counter了,就不再展开该点。
这一点能有效的控制环路。
如果一条路径上有一个小环,比如经过点A之后饶了一个小圈又经过A然后再往终点走,那么这条路径是走的很慢的,而其它的路径走的比它快的可能早就已经到达终点了。这个counter控制了每个点的settle次数,也就是说终点达到settle次数之后就停止搜索了,有可能其它路径走到终点了,而这条路径还没走到到时候,终点的settle次数就达到counter了,就停止搜索了,那么这条环路就算不出来了。当然,如果其它的路都非常非常远,而这条路很近,绕几个环路了还比别人近,那也会搜出来。
去掉环路后处理思路。比如到达点A时,发现它的parent是B,如果它已经有是B的记录了,那么就只保留一个就好了。这样就不会多次从B到A。
这样是不可行的! 这样不仅去掉了环路,也去掉了可能需要保留的路径,比如E到F到B到A和G到H到B到A我们都需要的话,这样一弄就只有一条了。
4搜索停止条件
(1) open队列为空
(2) target点settle次数为counter
多方案求路
一种思路:CH碰撞得到的多方案
另一种思路:全搜索,对所有方案聚类,得出差异度稍大的多方案
如何聚类?
采用kmeans。 定义两条路径的距离:1-2*两条route重复边长/两条route长之和
怎么计算聚类中心呢?簇中心是使其它点到该点的方差和最小的点,由于这里距离都是正数,因此简化为距离之和最小。逐个点计算其它点到该点的距离,取和。找出和最小的那个点作为聚类中心。这里的点就是一条路径。