版权声明:Fashion Education https://blog.csdn.net/ModestCoder_/article/details/81910920
LuoGu例题
我参考了这篇博文
首先介绍普通的dijkstra算法
dijkstra用于求单源最短路,但不支持负权
dijkstra算法的过程中把点分成两类,定义蓝点为已确定最短路的点,白点为未确定最短路的点
操作为下:
- 确定起点s,s为蓝点,初始化dis[s]=0,其他的dis=maxlongint
- 在白点中找dis值最小的,它已确定最短路,标记为蓝点
- 进行松弛操作,把跟当前拿出来的那个点相连的点更新dis
- 重复2、3操作直到所有点都确定最短路
显然,dijkstra的时间复杂度为O(n^2)
发现2操作可以用堆优化到log级别
用小根堆维护dis值,每次取出堆中第一个,若没标记则进行后面的步骤
Code:
var
heap:array[0..1000000] of record
num,dis:longint;
end;
edge:array[0..1000000] of record
t,next,dis:longint;
end;
head,dis:array[0..1000000] of longint;
vis:array[0..1000000] of boolean;
n,m,s,x,y,z,i,e,len,num:longint;
procedure add(x,y,z:longint);
begin
inc(num);
edge[i].t := y;
edge[i].dis := z;
edge[i].next := head[x];
head[x] := num;
end;
procedure swap(var x,y:longint);
var
tmp:longint;
begin
tmp := x; x := y; y := tmp;
end;
procedure push(x,y:longint);
var
i:longint;
begin
inc(len);
heap[len].num := x; heap[len].dis := y;
i := len;
while i > 1 do
begin
if heap[i].dis < heap[i >> 1].dis then
begin
swap(heap[i].num,heap[i >> 1].num);
swap(heap[i].dis,heap[i >> 1].dis);
i := i >> 1;
end else break;
end;
end;
procedure pop;
var
i,x:longint;
begin
heap[1].num := heap[len].num;
heap[1].dis := heap[len].dis;
dec(len);
i := 1;
while (i << 1) <= len do
begin
if ((i << 1 or 1) > len) or (heap[i << 1].dis < heap[i << 1 or 1].dis) then
x := i << 1 else x := i << 1 or 1;
if heap[i].dis > heap[x].dis then
begin
swap(heap[i].num,heap[x].num);
swap(heap[i].dis,heap[x].dis);
i := x;
end else break;
end;
end;
begin
readln(n,m,s);
for i := 1 to m do
begin
readln(x,y,z);
add(x,y,z);
end;
for i := 1 to n do dis[i] := maxlongint;
dis[s] := 0;
len := 1;
heap[1].num := s;
heap[1].dis := 0;
while len > 0 do
begin
x := heap[1].num;
y := heap[1].dis;
pop;
if vis[x] then continue;
vis[x] := true;
i := head[x];
while i <> 0 do
begin
e := edge[i].t;
if dis[e] > y + edge[i].dis then
begin
dis[e] := y + edge[i].dis;
push(e,dis[e]);
end;
i := edge[i].next;
end;
end;
for i := 1 to n do write(dis[i],' ');
end.