【学习笔记】dijkstra堆优化

版权声明:Fashion Education https://blog.csdn.net/ModestCoder_/article/details/81910920

LuoGu例题
我参考了这篇博文
首先介绍普通的dijkstra算法
dijkstra用于求单源最短路,但不支持负权
dijkstra算法的过程中把点分成两类,定义蓝点为已确定最短路的点,白点为未确定最短路的点
操作为下:

  1. 确定起点s,s为蓝点,初始化dis[s]=0,其他的dis=maxlongint
  2. 在白点中找dis值最小的,它已确定最短路,标记为蓝点
  3. 进行松弛操作,把跟当前拿出来的那个点相连的点更新dis
  4. 重复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.

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/81910920