图的优先级搜索

上一篇博客里面提到了优先级搜索(priority first search),单独拿出来写一篇,因为优先级搜索可以适用大部分图搜算算法。所谓优先级搜索,是在图的遍历过程中,每次迭代都更新图中某些点或者是边的优先级,随着算法的不断推进调整,每次选取顶点或者边中优先级最高的那个元素进行访问。按照这种思想,深度优先搜索和广度优先搜索其实都可以纳入到这个框架中,因为他们的不同之处仅仅在于,每次选择点的时候,点的优先级策略是不同的。约定优先级数值越小,优先级越高。下面,给出优先级搜索的框架:

 1 template<typename Tv, typename Te> template<typename PU> void Graph<Tv, Te>::pfs(int s,PU prioUpdater)//优先级搜索
 2 {
 3     reset(); int clock = 0; int v = s;
 4     do
 5         if (stasus(v) == UNDISCOVERED)//遇到未发现的顶点
 6             PFS(v, clock);//执行一次pFS
 7     while (s != (v = (++v%n)));//做到不重不漏
 8 }
 9 template<typename Tv, typename Te> template<typename PU>//优先级更新器
10 void Graph<Tv, Te>::PFS(int s, PU prioUpdater)
11 {
12     priority(s) = 0; status(s) = VISITED; parent(s) = -1;
13     while (1)
14     {
15         for (int w = firstNbr(s); w > -1; w = nextNbr(s, w))//更新所有的邻接顶点
16             prioUpdater(this, s, w);
17         for(int shortest = INT_MAX, w = 0; w < n; w++)//在所有顶点中寻找优先级最低的顶点
18             if(status(w) == UNDISCOVERED)
19                 if (priority(w) < shortest)
20                 {
21                     shortest = priority(w);
22                     s = w;
23                 }
24         if (status(s) == VISITED) break;//优先级最高的顶点已经被访问
25         status(s) = VISITED; type(parent(s), s) = TREE;
26     }
27 }

优先级搜索的流程,可以总结如下:对于当前节点的所有邻居,按照某种更新策略,更新他们的优先级;然后,从所有的点中找出优先级最高的顶点进行访问;当取出的优先级最高的顶点已经访问完成,算法结束。这样我们同样得到了和之前相同的,图的一颗遍历树。算法每次迭代都要访问所有的n个节点,时间复杂度为O(n^2)。

下面,把BFS和DFS纳入这个框架中,它们的更新器如下:

 1 template <typename Tv, typename Te> struct BfsPU
 2 { 
 3     virtual void operator() ( Graph<Tv, Te>* g, int uk, int v ) 
 4     {
 5         if ( g->status ( v ) == UNDISCOVERED ) 
 6         if ( g->priority ( v ) > g->priority ( uk ) + 1 ) 
 7         {
 8              g->priority ( v ) = g->priority ( uk ) + 1; //更新优先级(数)
 9              g->parent ( v ) = uk; //更新父节点
10         } 
11     }
12 }

广度优先搜索,只需要每次将UNDISCOVERED的点,优先级设置为当前点优先级数+1,这样每次新发现的点都要比以前发现的点优先级低。

 template <typename Tv, typename Te> struct DfsPU
{ 
    virtual void operator() ( Graph<Tv, Te>* g, int uk, int v ) 
    {
         if ( g->status ( v ) == UNDISCOVERED ) 
         if ( g->priority ( v ) > g->priority ( uk ) - 1 ) 
         {
              g->priority ( v ) = g->priority ( uk ) - 1; //更新优先级(数)
              g->parent ( v ) = uk; //更新父节点
              return;//这里只要有一个节点更新就可以返回
         } 
     }
}        

深度优先搜索,每次新发现的顶点都比父亲节点优先级低。要注意的是,每当有一个节点的优先级发生了改变,就可以直接返回。

原文地址:https://www.cnblogs.com/lustar/p/7213711.html