您的位置:首页 > 其它

关于dijkstra+heap的实现

2014-07-29 10:42 387 查看
转自: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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: