【学习笔记】dijkstra堆优化

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.

2019.2.9 Update:

pascal转c++,完成c++版的dijkstra
Code:

/*
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
*/
#include 
#define res register int
#define ll long long
#define maxn 2 * 200010
using namespace std;
struct node {
	int u, len;
	bool operator < (const node &x) const {
		return x.len < len;
	}
};
struct Edge {
	int to, next, len;
} edge[maxn];
int n, m, s, head[maxn], dis[maxn], vis[maxn], num;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) w |= c == '-';
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

inline void add_edge(int x, int y, int z) { edge[++ num].to = y; edge[num].next = head[x]; edge[num].len = z; head[x] = num; }

int main() {
	//input
	n = read(), m = read(), s = read();
	for (res i = 1; i <= m; ++ i) {
		int x = read(), y = read(), z = read();
		add_edge(x, y, z);
	}
	
	//dijkstra
	memset(dis, 0x3f, sizeof(dis)); dis[s] = 0;
	priority_queue <node> q;
	q.push( (node) { s, 0 });
	while (!q.empty()) {
		node tmp = q.top(); q.pop();
		int u = tmp.u, len = tmp.len;
		if (vis[u]) continue;
		vis[u] = 1;
		for (res i = head[u]; i; i = edge[i].next) {
			int v = edge[i].to;
			if (dis[v] > len + edge[i].len){
				dis[v] = len + edge[i].len;
				q.push( (node) { v, dis[v] });
			}
		}
	}
	//output
	for (res i = 1; i <= n; ++ i) printf("%d ", dis[i]);
	return 0;
}

你可能感兴趣的:(最短路,学习笔记)