转自: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);
}