使用C ++ stl中的向量和对最有效地实现Dijkstra的最短路径

时间:2017-04-11 16:41:51

标签: c++ algorithm vector stl dijkstra

如果std::vector<vector<pair<int,int> > > v(n)代表pair<int,int>{vertex,weight}对的图表的邻接列表,我尝试按以下方式实施该算法:

while (true)
{
    long long yo = LLONG_MAX;
    int ind = -1;
    for (int i = 0; i < n; ++i)
    {
        if (ans[i] < yo && !v[i].empty())
        {
            ind = i;
            yo = ans[i];
        }
    }
    if (ind == -1)
        break;
    for (int i = 0; i < v[ind].size(); ++i)
    {
        if (ans[v[ind][i].first] > ans[ind] + v[ind][i].second)
            ans[v[ind][i].first] = ans[ind] + v[ind][i].second;
        v[ind].erase(v[ind].begin() + i);
    }
}

ans[i]存储初始化为{LLONG_MAX,...0,...LLONG_MAX}的最短路径,0为源。由于这是我第一次尝试实现它,有没有更好的方法来实现使用stl中的vectors / list(可能在时间/空间复杂度方面)?

2 个答案:

答案 0 :(得分:0)

当前的方法有逻辑错误(在迭代时修改向量)。 同样复杂性似乎非常糟糕,因为冗余的while循环每次获得新的最小距离节点和不必要的擦除操作,由于整个邻接列表的移位而导致向量很大。

我建议使用优先级队列&lt; min heap&gt;,它更清晰,复杂度为Elog(N),其中E为no。边缘和N没有。图中的节点。 我只是复制粘贴我的一个旧代码和评论。

#define P first
#define Q second 
typedef long long LL ;
typedef pair < LL , int > li ;
typedef pair < int , LL > il ;
dist[N] = {INT_MAX} ;  // array containing the distance to each node from source node 
vector < il > adj [100010] ; // adjacency list with (node, distance) pair 

void dijkstra( int s ){   // s is the source node
  priority_queue < li , vector < li > , greater < li > > pq; // priortiy queue with a pair <long, int> as the data , using vector as underlying data structure and std:greater comparator 
  dist [s] = 0;
  pq.push( li( dist[s], s) );
  while( !pq.empty() ){
      li u = pq.top() ; pq.pop() ; // u.P =  current minimum distance of node , u.Q = current node on top of the heap 
      if( dist[u.Q] == u.P )
      for( int i = 0 ; i  < adj[u.Q].size() ; i++){
           il v = adj[u.Q][i] ;
           if( dist[v.P] > u.P + v.Q ){
               dist[v.P] = u.P + v.Q ;
               pq.push( li(dis[v.P] ,v.P ));
           }
      } 
  }

如果您有任何疑问,请随时在评论中提问。

答案 1 :(得分:0)

优化Dijkstra的一些方法:

  1. 使用堆。确保存储顶点,而不是堆中的边。
  2. 尝试双向方法。假设,您必须找到从S到T的最短路径。您可以同时运行2个Dijkstra:一个像往常一样来自S,另一个来自T在反向边缘。你可以使用某种启发式方法在这两个Dijkstras之间切换。例如,使用当前半径最小的Dijkstra。
  3. 理论上,Dijkstra可以用Fibonacci堆优化到O(E + VlogV)。但实际上它的工作速度较慢。