关于dijkstra+heap的实现

转自:http://blog.csdn.net/biran007/archive/2009/04/17/4088132.aspx

大家说道dijkstra就不得不提它的heap优化。但是具体怎么实现呢?

C++ STL提供了priority_queue, 支持push,top,pop操作。但是光靠这三个函数还不足以实现dijkstra的优化。

回想dijkstra算法中,for(1..v)的大循环内,每次在unknown的集合中找到dist[]数组里最小的那个,从unknown集合中删除该结点。朴素实现需要O(V)的时间,而用堆可以用O(log(V))的时间找到。然而,光找到还没完,找到之后要松弛所有与他相邻的unknown的结点(known的结点已经都是最短路了)。注意到如果要用堆实现优化,堆中存储的结点的priority值应当是图中该店当前的离source的距离。然而松弛操作会更新该距离,这就意味着我们要到堆内部找到这个结点的位置,更新距离,再维护堆。而堆是不提供检索功能的,找到一个结点需要O(V),完全糟蹋了O(log V)的优化了。更何况STL的priority_queue没有办法去接触内部的数据了。

其实,有一个可行的解决方案:一旦某个结点被更新了距离,一律但当成新结点加进堆里。这样会造成一个一个问题:一个图中的结点可能在堆中可能同时会存在好几个。但是这个不影响结果:先出堆的一定是距离最小的那个结点。其他的结点出堆的时候图里面的对应结点一定已经在known的集合了,到时候直接无视掉弹出来的已经known的结点,继续弹下一个,知道弹出一个unknown的结点为止。

这个做法最坏可能会让堆的高度加倍,然是任然不影响O(log n)的复杂度。不过具体的复杂度计算貌似不那么简单……不过实践证明速度确实有了很大提高,尤其是对于稀疏图。

这种实现用STL的priority_queue也能完成,程序也只是在naive的dijkstra上加几行,性价比不错。

而真正的dijkstra+heap也是可以实现的。问题的关键集中在 reduce_to(int ID,int value) 的操作。这要求我们自己实现一个堆。堆的结点需要保存2个数据,一个是对应图中结点的标号ID,一个是对应图中结点的距离dist。而要支持reduce,我们需要一个映射location,使得location[ID]=要找的结点在堆中的位置,这个可以用数组实现。需要注意的是,在维护堆的同时,也需要维护location映射。其实只要在维护堆heap+dijkstra与SPFA都是单源最短路的高效算法,到底谁比较快一直各有各的说法。于是心血来潮自己测试了下。

测试工具:cena 0.6

系统: windows vista

CPU: T2130, 1.86Ghz

所有程序中,图用相同格式存储,输入,输出,数据都是静态分配

邻接表参考dd的dinic代码

Dijkstra1: 我写的的支持内部修改的heap,

复杂度O((V+E)logV)

Dijkstra2: STL的priority_queue,更新之后结点直接加进堆中而不是更新堆内的结点

复杂度: ???

Dijkstra3: 朴素的Dijkstra

复杂度O(V^2+E)

SPFA:        经典的bellmen-ford的优化,用的最常见的写法,自己写的queue  

复杂度O(k*E), k接近2

USACO:       usaco中butter一题的标程稍作修改,本质与Dijkstra1相似,

复杂度O((V+E)logV)

TEST 1:2000个点的完全图

输入输出用时:2.15-2.9秒, 平均:2.47

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.13  0.10

Dijkstra2: 0.05  0.41

Dijkstra3: 0.21  0.18

SPFA:        1.04  0.97

USACO:       0.29  0.40

大规模密集图,大量数据的输入输出占用了大部分时间。单纯计算时间太短难以比较。几种dijkstra都有很好的表现,SPFA由于运行时间对于边数的依赖性,显得逊色不少。

对于Dijkstra1和Dijkstra2 因为是密集图,每次找到一个点后无论是内部更新还是重新插入结点,都要O(log n)的复杂度(虽然插入结点的期望复杂度为O(1),但是由于是重新插入结点,堆内同时存在的总结点数可能会达到E的数量级,增大了常数),工作量都是较大的,堆的优势没有体现出来。 相比之下,朴素的Dijkstra的表现相当不错。

TEST 2: 100000个结点的链状图

输入输出用时:0.10 – 0.30秒, 平均:0.17

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.03  0.07

Dijkstra2: 0.04  0.07

Dijkstra3: >10   >10

SPFA:        0.03  0.00

USACO:       0.15  0.18

对于极端的链状图,SPFA无疑是最合适的了。每个结只进队一次,标准的O(E)。朴素的dijkstra对于这样的图就力不从心了:每次循环都过一遍结点,在松弛,然后发现每次O(V)的时间只松弛了一个点。。

Dijkstra2 由于堆内的结点总数最多有E的数量级,稀疏图里和V接近,劣势没有体现出来。

TEST 3: 20000个结点的稀疏图(每个点100条边)

输入输出用时:2.15-2.40 秒, 平均:2.30

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.33

Dijkstra2: 0.39  0.57

Dijkstra3: 2.20  3.26

SPFA:        5.45  5.11

USACO:       0.27  0.33

普通的稀疏图,比TEST 2的密集。 Dijkstra+heap依然是最快的。

比较惊奇的结果是:SPFA居然会比朴素dijkstra还慢……有些出乎预料

原因还没想明白……

TEST 3: 5000个结点的较密集图(每个点500条边)

输入输出用时:2.44-2.99 秒, 平均:2.75

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.32

Dijkstra2: 0.39  0.33

Dijkstra3: 0.40  0.40

SPFA:        1.04  1.04

USACO:       0.40  0.19

比较密集的图。SPFA的表现仍然不佳,Dijkstra+heap 任然是王道,朴素dijkstra的劣势逐渐缩小

总结:

Dijkstra1对于各种图都有良好表现,但是编程复杂度较高,需要准备模板。Dijkstra2速度也很不错,普遍略逊于Dijkstra1。Dijkstra3对于密集图有不错的表现。

SPFA表现不尽如人意。但是由于SPFA编程复杂度低,适用于各种图,也可以用来负权环,适合比赛使用。

编程复杂度:SPFA>naive dijkstra>STLheap+dijkstra>heap+dijkstra(越靠前越容易是写)

综合效率:   heap+dijkstra>STLheap+dijkstra> SPFA>naive dijkstra

比赛的时候 STLheap+dijkstra 和 SPFA 是不错的选择

dijkstra1:

view plaincopy to clipboardprint?
#include<iostream>   
using namespace std;   
struct MinBinaryHeap{   
       struct node{   
            int key;              
            int value;   
            inline bool operator<(const node &t)const{   
                 return value < t.value;      
            }            
       }*array;   
       int *location,heap_size;   
       MinBinaryHeap(int size){   
            heap_size=0;   
            array=new node[size+1];   
            location=new int[size];   
       }          
       ~MinBinaryHeap(){   
            delete[] array;    
            delete[] location;   
       }   
       inline void update(int loc,const node& x){ //put x into array[loc]   
            array[loc]=x;   
            location[x.key]=loc;     
       }   
       void per_down(int hole){   
            node tem=array[hole];       
            while(1){      
                int child=hole<<1;        
                if(child > heap_size)   
                   break;   
                if(child!=heap_size && array[child+1] < array[child])   
                   child++;   
                if(array[child] < tem){   
                   update(hole,array[child]);   
                   hole=child;        
                }else break;   
            }   
            update(hole,tem);   
       }          
       void per_up(int hole){   
            node tem=array[hole];      
            while(hole > 1){   
                if(tem < array[hole>>1]){   
                   update(hole,array[hole>>1]);   
                   hole>>=1;   
               }else break;   
            }   
            update(hole,tem);   
       }   
       void build_heap(int *values, int n){   
            heap_size=n;   
            for(int i=1;i<=n;i++){   
                array[i].key=i-1;   
                array[i].value=*(values++);     
                location[array[i].key]=i;   
            }   
            for(int i=heap_size>>1;i>=1;i–)   
                per_down(i);               
       }   
       pair<int,int> pop(){   
            pair<int,int> res=make_pair(array[1].key,array[1].value);       
            array[1]=array[heap_size–];   
            per_down(1);   
            return res;;   
       }   
       void decrease_to(int key,int value){   
            array[location[key]].value=value;      
            per_up(location[key]);     
       }   
};   
const int maxn=100000,INF=0x11111111;;   
struct graph{   
       int node_num,allop_pt;   
       struct edge{   
              int j,w;   
              edge *next;   
       }*g[maxn],*pool;   
       graph(int node_num,int edge_num):node_num(node_num){   
               memset(g,0,sizeof(g));   
               pool=new edge[2*edge_num];   
               allop_pt=0;   
       }   
       ~graph(){   
               delete[] pool;              
       }   
       inline edge* new_edge(int j,int w,edge* next){   
             pool[allop_pt].j=j;   
             pool[allop_pt].w=w;   
             pool[allop_pt].next=next;   
             return &pool[allop_pt++];   
       }   
       inline void add_edge(int i,int j,int w){   
               g[i]=new_edge(j,w,g[i]);   
               g[j]=new_edge(i,w,g[j]);   
       }          
};   
void dijkstra(graph& g,int source, int dis[]){   
     bool known[maxn]={0};   
     for(int i=0;i<g.node_num;i++)dis[i]=INF;   
     dis[source]=0;   
     MinBinaryHeap heap(g.node_num);   
     heap.build_heap(dis,g.node_num);   
     for(int k=0;k<g.node_num;k++){   
         pair<int,int> tem=heap.pop();           
         int i=tem.first;   
         known[i]=true;   
         for(graph::edge* e=g.g[i];e;e=e->next){   
                 if(!known[e->j] && dis[e->j] > dis[i]+e->w){     
                    dis[e->j]=dis[i]+e->w;   
                    heap.decrease_to(e->j,dis[e->j]);   
                 }   
         }   
     }   
}  
#include<iostream>
using namespace std;
struct MinBinaryHeap{
    struct node{
         int key;           
   int value;
   inline bool operator<(const node &t)const{
     return value < t.value;   
      }    
       }*array;
    int *location,heap_size;
    MinBinaryHeap(int size){
      heap_size=0;
          array=new node[size+1];
          location=new int[size];
       }    
    ~MinBinaryHeap(){
          delete[] array; 
          delete[] location;
       }
       inline void update(int loc,const node& x){ //put x into array[loc]
            array[loc]=x;
   location[x.key]=loc;  
       }
       void per_down(int hole){
            node tem=array[hole];  
      while(1){ 
                int child=hole<<1;  
                if(child > heap_size)
       break;
          if(child!=heap_size && array[child+1] < array[child])
             child++;
                if(array[child] < tem){
          update(hole,array[child]);
       hole=child;     
       }else break;
   }
   update(hole,tem);
    }       
    void per_up(int hole){
            node tem=array[hole]; 
      while(hole > 1){
       if(tem < array[hole>>1]){
          update(hole,array[hole>>1]);
       hole>>=1;
      }else break;
   }
   update(hole,tem);
    }
       void build_heap(int *values, int n){
         heap_size=n;
      for(int i=1;i<=n;i++){
       array[i].key=i-1;
    array[i].value=*(values++);  
    location[array[i].key]=i;
   }
      for(int i=heap_size>>1;i>=1;i–)
       per_down(i);   
    }
    pair<int,int> pop(){
      pair<int,int> res=make_pair(array[1].key,array[1].value);    
       array[1]=array[heap_size–];
       per_down(1);
   return res;;
    }
    void decrease_to(int key,int value){
      array[location[key]].value=value; 
      per_up(location[key]); 
    }
};
const int maxn=100000,INF=0x11111111;;
struct graph{
    int node_num,allop_pt;
    struct edge{
        int j,w;
        edge *next;
       }*g[maxn],*pool;
       graph(int node_num,int edge_num):node_num(node_num){
         memset(g,0,sizeof(g));
         pool=new edge[2*edge_num];
         allop_pt=0;
       }
       ~graph(){
            delete[] pool;   
    }
    inline edge* new_edge(int j,int w,edge* next){
       pool[allop_pt].j=j;
       pool[allop_pt].w=w;
       pool[allop_pt].next=next;
       return &pool[allop_pt++];
       }
    inline void add_edge(int i,int j,int w){
         g[i]=new_edge(j,w,g[i]);
         g[j]=new_edge(i,w,g[j]);
       }    
};
void dijkstra(graph& g,int source, int dis[]){
  bool known[maxn]={0};
  for(int i=0;i<g.node_num;i++)dis[i]=INF;
  dis[source]=0;
  MinBinaryHeap heap(g.node_num);
  heap.build_heap(dis,g.node_num);
  for(int k=0;k<g.node_num;k++){
      pair<int,int> tem=heap.pop();  
      int i=tem.first;
      known[i]=true;
      for(graph::edge* e=g.g[i];e;e=e->next){
      if(!known[e->j] && dis[e->j] > dis[i]+e->w){  
         dis[e->j]=dis[i]+e->w;
         heap.decrease_to(e->j,dis[e->j]);
              }
   }
     }
}

dijkstra2:

view plaincopy to clipboardprint?
#include<stdio.h>   
#include<queue>   
#include<string.h>   
#include<vector>   
using namespace std;   
const int maxn=100000,INF=0x11111111;   
struct graph{   
       int node_num,allop_pt;   
       struct edge{   
              int j,w;   
              edge *next;   
       }*g[maxn],*pool;   
       graph(int node_num,int edge_num):node_num(node_num){   
               memset(g,0,sizeof(g));   
               pool=new edge[2*edge_num];   
               allop_pt=0;   
       }   
       ~graph(){   
               delete[] pool;              
       }   
       inline edge* new_edge(int j,int w,edge* next){   
             pool[allop_pt].j=j;   
             pool[allop_pt].w=w;   
             pool[allop_pt].next=next;   
             return &pool[allop_pt++];   
       }   
       inline void add_edge(int i,int j,int w){   
               g[i]=new_edge(j,w,g[i]);   
               g[j]=new_edge(i,w,g[j]);   
       }          
};   
struct node{   
   int v,dis;   
   node(int v,int dis):v(v),dis(dis){}   
   inline bool operator<(const node &b) const{   
      return dis>b.dis;   
   }          
};   
void dijkstra(graph& g,int source, int dis[]){   
     priority_queue<node> heap;   
     heap.push(node(source,0));   
     bool known[maxn]={0};   
     for(int i=0;i<g.node_num;i++)   
            dis[i]=INF;   
     dis[source]=0;          
     for(int i=0;i<g.node_num;i++){   
            int u,v,w;   
            do{   
                node t=heap.top();   
                u=t.v;   
                heap.pop();    
            }while(known[u]);   
            known[u]=true;   
            for(graph::edge *e=g.g[u];e;e=e->next){   
                 v=e->j;w=e->w;   
                 if(!known[v] && dis[v]>dis[u]+w){   
                     dis[v]=dis[u]+w;         
                     heap.push(node(v,dis[v]));         
                 }   
            }       
     }   
}   
int main(){   
       freopen(“in.txt”,”r”,stdin);   
       freopen(“out.txt”,”w”,stdout);   
       int dis[maxn];   
       int n,m,a,b,c;   
       scanf(“%d%d”,&n,&m);   
       graph G(n,m);   
       while(m–){   
                  scanf(“%d%d%d”,&a,&b,&c);   
                  G.add_edge(a,b,c);   
       }   
       dijkstra(G,0,dis);   
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);   
}  
#include<stdio.h>
#include<queue>
#include<string.h>
#include<vector>
using namespace std;
const int maxn=100000,INF=0x11111111;
struct graph{
    int node_num,allop_pt;
    struct edge{
        int j,w;
        edge *next;
       }*g[maxn],*pool;
       graph(int node_num,int edge_num):node_num(node_num){
         memset(g,0,sizeof(g));
         pool=new edge[2*edge_num];
         allop_pt=0;
       }
       ~graph(){
            delete[] pool;   
    }
    inline edge* new_edge(int j,int w,edge* next){
       pool[allop_pt].j=j;
       pool[allop_pt].w=w;
       pool[allop_pt].next=next;
       return &pool[allop_pt++];
       }
    inline void add_edge(int i,int j,int w){
         g[i]=new_edge(j,w,g[i]);
         g[j]=new_edge(i,w,g[j]);
       }    
};
struct node{
   int v,dis;
   node(int v,int dis):v(v),dis(dis){}
   inline bool operator<(const node &b) const{
      return dis>b.dis;
   }       
};
void dijkstra(graph& g,int source, int dis[]){
     priority_queue<node> heap;
     heap.push(node(source,0));
     bool known[maxn]={0};
     for(int i=0;i<g.node_num;i++)
            dis[i]=INF;
     dis[source]=0;       
     for(int i=0;i<g.node_num;i++){
            int u,v,w;
            do{
                node t=heap.top();
                u=t.v;
                heap.pop(); 
            }while(known[u]);
            known[u]=true;
            for(graph::edge *e=g.g[u];e;e=e->next){
                 v=e->j;w=e->w;
                 if(!known[v] && dis[v]>dis[u]+w){
                     dis[v]=dis[u]+w;      
                     heap.push(node(v,dis[v]));      
                 }
            }    
     }
}
int main(){
    freopen(“in.txt”,”r”,stdin);
    freopen(“out.txt”,”w”,stdout);
       int dis[maxn];
       int n,m,a,b,c;
       scanf(“%d%d”,&n,&m);
       graph G(n,m);
       while(m–){
         scanf(“%d%d%d”,&a,&b,&c);
         G.add_edge(a,b,c);
       }
       dijkstra(G,0,dis);
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);
}
 

dijkstra3:

view plaincopy to clipboardprint?
#include<stdio.h>   
#include<queue>   
#include<string.h>   
using namespace std;   
const int maxn=100000,INF=0x11111111;;   
struct graph{   
       int node_num,allop_pt;   
       struct edge{   
              int j,w;   
              edge *next;   
       }*g[maxn],*pool;   
       graph(int node_num,int edge_num):node_num(node_num){   
               memset(g,0,sizeof(g));   
               pool=new edge[2*edge_num];   
               allop_pt=0;   
       }   
       ~graph(){   
               delete[] pool;              
       }   
       inline edge* new_edge(int j,int w,edge* next){   
             pool[allop_pt].j=j;   
             pool[allop_pt].w=w;   
             pool[allop_pt].next=next;   
             return &pool[allop_pt++];   
       }   
       inline void add_edge(int i,int j,int w){   
               g[i]=new_edge(j,w,g[i]);   
               g[j]=new_edge(i,w,g[j]);   
       }          
};   
int dis[maxn];   
void dijkstra(graph &g,int source,int dis[]){   
     bool known[maxn]={0};   
     for(int i=0;i<g.node_num;i++)dis[i]=INF;   
     dis[source]=0;   
     for(int i=0;i<g.node_num;i++){   
            int u,v,w,min=INF;   
            for(int i=0;i<g.node_num;i++)   
                    if(!known[i] && min>dis[i]){   
                         min=dis[i];   
                         u=i;                 
                    }   
            known[u]=true;   
            for(graph::edge *e=g.g[u];e;e=e->next){   
                 v=e->j,w=e->w;   
                 if(!known[v] && dis[v]>dis[u]+w)   
                     dis[v]=dis[u]+w;          
            }      
     }   
}   
int main(){   
       freopen(“in.txt”,”r”,stdin);   
       freopen(“out.txt”,”w”,stdout);   
       int n,m,a,b,c;   
       scanf(“%d%d”,&n,&m);   
       graph G(n,m);   
       while(m–){   
                  scanf(“%d%d%d”,&a,&b,&c);   
                  G.add_edge(a,b,c);   
       }   
       dijkstra(G,0,dis);   
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);   
}  
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
const int maxn=100000,INF=0x11111111;;
struct graph{
    int node_num,allop_pt;
    struct edge{
        int j,w;
        edge *next;
       }*g[maxn],*pool;
       graph(int node_num,int edge_num):node_num(node_num){
         memset(g,0,sizeof(g));
         pool=new edge[2*edge_num];
         allop_pt=0;
       }
       ~graph(){
            delete[] pool;   
    }
    inline edge* new_edge(int j,int w,edge* next){
       pool[allop_pt].j=j;
       pool[allop_pt].w=w;
       pool[allop_pt].next=next;
       return &pool[allop_pt++];
       }
    inline void add_edge(int i,int j,int w){
         g[i]=new_edge(j,w,g[i]);
         g[j]=new_edge(i,w,g[j]);
       }    
};
int dis[maxn];
void dijkstra(graph &g,int source,int dis[]){
     bool known[maxn]={0};
     for(int i=0;i<g.node_num;i++)dis[i]=INF;
     dis[source]=0;
     for(int i=0;i<g.node_num;i++){
            int u,v,w,min=INF;
            for(int i=0;i<g.node_num;i++)
     if(!known[i] && min>dis[i]){
          min=dis[i];
       u=i;      
              }
            known[u]=true;
            for(graph::edge *e=g.g[u];e;e=e->next){
                 v=e->j,w=e->w;
                 if(!known[v] && dis[v]>dis[u]+w)
                     dis[v]=dis[u]+w;       
            }   
     }
}
int main(){
    freopen(“in.txt”,”r”,stdin);
    freopen(“out.txt”,”w”,stdout);
       int n,m,a,b,c;
       scanf(“%d%d”,&n,&m);
       graph G(n,m);
       while(m–){
         scanf(“%d%d%d”,&a,&b,&c);
         G.add_edge(a,b,c);
       }
       dijkstra(G,0,dis);
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);
}
 

SPFA:

view plaincopy to clipboardprint?
#include<stdio.h>   
#include<string.h>   
using namespace std;   
const int maxn=100000,INF=0x11111111;;   
struct graph{   
       int node_num,allop_pt;   
       struct edge{   
              int j,w;   
              edge *next;   
       }*g[maxn],*pool;   
       graph(int node_num,int edge_num):node_num(node_num){   
               memset(g,0,sizeof(g));   
               pool=new edge[2*edge_num];   
               allop_pt=0;   
       }   
       ~graph(){   
               delete[] pool;              
       }   
       inline edge* new_edge(int j,int w,edge* next){   
             pool[allop_pt].j=j;   
             pool[allop_pt].w=w;   
             pool[allop_pt].next=next;   
             return &pool[allop_pt++];   
       }   
       inline void add_edge(int i,int j,int w){   
               g[i]=new_edge(j,w,g[i]);   
               g[j]=new_edge(i,w,g[j]);   
       }          
};   
int Q[65536];   
void SPFA(graph &g,int source,int dis[]){   
       int qsize=65535,f=0,b=0;   
       bool in[maxn]={0};   
       for(int i=0;i<g.node_num;i++)dis[i]=INF;   
       dis[source]=0;   
       Q[f++]=source;f&=qsize;   
       in[source]=true;   
       while(f!=b){   
            int i=Q[b++];b&=qsize;   
            in[i]=false;   
            for(graph::edge *e=g.g[i];e;e=e->next){   
                 if(dis[e->j] > dis[i]+e->w){     
                     dis[e->j]=dis[i]+e->w;      
                     if(!in[e->j]){   
                        Q[f++]=e->j;f&=qsize;   
                        in[e->j]=true;                 
                     }   
                 }     
            }                       
       }        
}   
int main(){   
       freopen(“in.txt”,”r”,stdin);   
       freopen(“out.txt”,”w”,stdout);   
       int dis[maxn];   
       int n,m,a,b,c;   
       scanf(“%d%d”,&n,&m);   
       graph G(n,m);   
       while(m–){   
                  scanf(“%d%d%d”,&a,&b,&c);   
                  G.add_edge(a,b,c);   
       }   
       SPFA(G,0,dis);   
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);   
}  
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=100000,INF=0x11111111;;
struct graph{
    int node_num,allop_pt;
    struct edge{
        int j,w;
        edge *next;
       }*g[maxn],*pool;
       graph(int node_num,int edge_num):node_num(node_num){
         memset(g,0,sizeof(g));
         pool=new edge[2*edge_num];
         allop_pt=0;
       }
       ~graph(){
            delete[] pool;   
    }
    inline edge* new_edge(int j,int w,edge* next){
       pool[allop_pt].j=j;
       pool[allop_pt].w=w;
       pool[allop_pt].next=next;
       return &pool[allop_pt++];
       }
    inline void add_edge(int i,int j,int w){
         g[i]=new_edge(j,w,g[i]);
         g[j]=new_edge(i,w,g[j]);
       }    
};
int Q[65536];
void SPFA(graph &g,int source,int dis[]){
    int qsize=65535,f=0,b=0;
    bool in[maxn]={0};
    for(int i=0;i<g.node_num;i++)dis[i]=INF;
    dis[source]=0;
    Q[f++]=source;f&=qsize;
    in[source]=true;
    while(f!=b){
         int i=Q[b++];b&=qsize;
   in[i]=false;
   for(graph::edge *e=g.g[i];e;e=e->next){
           if(dis[e->j] > dis[i]+e->w){  
          dis[e->j]=dis[i]+e->w; 
          if(!in[e->j]){
         Q[f++]=e->j;f&=qsize;
      in[e->j]=true;      
            }
           } 
   }      
       }  
}
int main(){
    freopen(“in.txt”,”r”,stdin);
    freopen(“out.txt”,”w”,stdout);
       int dis[maxn];
       int n,m,a,b,c;
       scanf(“%d%d”,&n,&m);
       graph G(n,m);
       while(m–){
         scanf(“%d%d%d”,&a,&b,&c);
         G.add_edge(a,b,c);
       }
       SPFA(G,0,dis);
       for(int i=0;i<n;i++)printf(“%d/n”,dis[i]);
}
 

USACO:

view plaincopy to clipboardprint?
#include <stdio.h>   
#include <string.h>   
const int BIG = 1000000000;   
const int maxn = 100000;   
int v,e;   
struct graph{   
       int node_num,allop_pt;   
       struct edge{   
              int j,w;   
              edge *next;   
       }*g[maxn],*pool;   
       graph(int node_num,int edge_num):node_num(node_num){   
               memset(g,0,sizeof(g));   
               pool=new edge[2*edge_num];   
               allop_pt=0;   
       }   
       ~graph(){   
               delete[] pool;              
       }   
       inline edge* new_edge(int j,int w,edge* next){   
             pool[allop_pt].j=j;   
             pool[allop_pt].w=w;   
             pool[allop_pt].next=next;   
             return &pool[allop_pt++];   
       }   
       inline void add_edge(int i,int j,int w){   
               g[i]=new_edge(j,w,g[i]);   
               g[j]=new_edge(i,w,g[j]);   
       }          
};   
int dist[maxn];   
int heapsize;   
int heap_id[maxn];   
int heap_val[maxn];   
int heap_lookup[maxn];   
void heap_swap(int i, int j){   
    int s;   
    s = heap_val[i];   
    heap_val[i] = heap_val[j];   
    heap_val[j] = s;   
    heap_lookup[heap_id[i]] = j;   
    heap_lookup[heap_id[j]] = i;   
    s = heap_id[i];   
    heap_id[i] = heap_id[j];   
    heap_id[j] = s;   
}   
void heap_up(int i){   
    if(i > 0 && heap_val[(i-1) / 2] > heap_val[i]){   
        heap_swap(i, (i-1)/2);   
        heap_up((i-1)/2);   
    }   
}   
void heap_down(int i){   
    int a = 2*i+1;   
    int b = 2*i+2;   
    if(b < heapsize){   
        if(heap_val[b] < heap_val[a] && heap_val[b] < heap_val[i]){   
            heap_swap(i, b);   
            heap_down(b);   
            return;   
        }   
    }   
    if(a < heapsize && heap_val[a] < heap_val[i]){   
        heap_swap(i, a);   
        heap_down(a);   
    }   
}   
int main(){   
    freopen(“in.txt”,”r”,stdin);   
    freopen(“out.txt”,”w”,stdout);   
    scanf(“%d%d”,&v,&e);   
    graph g(v,e);   
    int a,b,c;   
    for(int i = 0; i < e; ++i){   
        scanf( “%d%d%d”,&a,&b,&c);   
        g.add_edge(a,b,c);   
    }   
       
    int i=0;   
    heapsize = v;   
    for(int j = 0; j < v; ++j){   
        heap_id[j] = j;   
        heap_val[j] = BIG;   
        heap_lookup[j] = j;   
    }   
    heap_val[i] = 0;   
    heap_up(i);   
       
    bool fixed[maxn];   
    memset(fixed, false, v);   
    for(int j = 0; j < v; ++j){   
        int p = heap_id[0];   
        dist[p] = heap_val[0];   
        fixed[p] = true;   
        heap_swap(0, heapsize-1);   
        –heapsize;   
        heap_down(0);   
        for(graph::edge *e=g.g[p];e;e=e->next){   
            int q = e->j;   
            if(!fixed[q]){   
                if(heap_val[heap_lookup[q]] > dist[p] + e->w){   
                    heap_val[heap_lookup[q]] = dist[p] + e->w;   
                    heap_up(heap_lookup[q]);   
                }   
            }   
        }   
    }   
    for(int i=0;i<v;i++)printf(“%d/n”,dist[i]);   
    return(0);   

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/geguojun/article/details/38260539
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞