算法学习 - Dijkstra(迪杰斯特拉)算法学习

来源:互联网 发布:浩浩乎如冯虚御风的乎 编辑:程序博客网 时间:2024/06/06 08:53

Dijkstra算法

其实Dijkstra是单源点最短路径的基础算法,这个算法的目的就是找到一个图中的某个点V到这个图中其他点的最短路径。

条件


  • 有向图
  • 没有负权值路径

时间复杂度:O(E) + O(V^2) = O(V^2)
当图是稠密的时候和稀疏的时候时间复杂度还是有点差别的。

原理

原理是这样的,首先最开始所有节点都是未知的,距离未知,初始化起始节点的距离为0, 其他节点都是不可达(用最大整数,或者-1表示)。然后每次找到所有未知节点中距离最小的那个节点(minNode 节点),标记为已知,已这个节点为起始,松弛所有挨着它的节点。

依次类推,每次都找所有未知节点中距离最小的节点。标记为已知,然后松弛操作。

代码实现

其实这个还挺简单的,单源点最短路径还有一个Bellman-Ford算法,以后在写,比较简单。

Dijkstra算法:

////  main.cpp//  Dijkstra////  Created by Alps on 15/3/4.//  Copyright (c) 2015年 chen. All rights reserved.//#include <iostream>#ifndef NumVertex#define NumVertex 4 //定义图的顶点数量#endif#ifndef Infinity#define Infinity 10000 //定义权值最大值#endifusing namespace std;typedef int  Vertex;struct LinkList{ //定义邻接链表    int val;    int length;    LinkList * next;    LinkList(int v): val(v), next(NULL) {}};typedef LinkList* List;struct TableEntry{ //定义结构体用来实现算法。    List Header;    bool Know;    int Dist;    Vertex Path;};typedef struct TableEntry Table[NumVertex+1]; //定义结构体所存储的图void InitTable(Vertex Start, Table T){ //初始化    List temp;    int OutDegree;    for (int i = 1; i <= NumVertex; i++) {        T[i].Know = false;        T[i].Dist = Infinity;        T[i].Path = -1;        T[i].Header = NULL;        scanf("%d",&OutDegree);        for (int j = 0; j < OutDegree; j++) {            temp = (List)malloc(sizeof(struct LinkList));            scanf("%d %d",&(temp->val), &(temp->length));            temp->next = T[i].Header;            T[i].Header = temp;        }    }    T[Start].Dist = 0;}void PrintPath (Vertex V,Table T){ //打印路径    if (T[V].Path != -1) {        PrintPath(T[V].Path, T);        printf(" to ");    }    printf("%d", V);}Vertex SmallDistUnknow(Table T){ //查找当前已知顶点到未知顶点路径的最小值    int MinDist = Infinity + 1, V = 0;    for (int i = 1; i <= NumVertex; i++) {        if (!T[i].Know && T[i].Dist <= MinDist) {            MinDist = T[i].Dist;            V = i;        }    }    return V;}void Dijkstra(Table T){ //算法主题    List temp;    Vertex V;    while (1) {        V = SmallDistUnknow(T);        if (V == 0) {            break;        }        T[V].Know = true;        temp = T[V].Header;        while (temp != NULL) {            if (!T[temp->val].Know) {                if (T[V].Dist + temp->length < T[temp->val].Dist) {                    T[temp->val].Dist = T[V].Dist + temp->length;                    T[temp->val].Path = V;                }            }            temp = temp->next;        }    }}int main(int argc, const char * argv[]) {    Table T;    InitTable(1, T);    Dijkstra(T);    PrintPath(2, T);//    std::cout << "Hello, World!\n";    return 0;}

二维数组实现

最近在刷题,刚好有个用邻接矩阵存图的方式实现了一下,所以可以参考一下。

原理一样,只不过存放的时候,用了一个flag表示了节点是否已知,用了len数组存放起点到这些节点的距离。

////  main.cpp//  HiHocoder////  Created by Alps on 16/5/9.//  Copyright © 2016年 chen. All rights reserved.//#include <iostream>#include <cstring>#include <string>using namespace std;long long dist[1002][1002];int flag[1002];long long len[1002];long long minNum(long long a, long long  b){    if(a == -1) return b;    return a < b ? a : b;}int minNode(int N){    long long minnum = -1;    int nodenum = -1;    for(int i = 1; i <= N; i++){        if(flag[i] == -1 && len[i] != -1){            if(minnum == -1 || minnum >= len[i]){                minnum = len[i];                nodenum = i;            }        }    }    return nodenum;}void dijkstra(long long dist[][1002], int N, int S){    len[S] = 0;    while(1){        int cur = minNode(N);        if(cur == -1) return;        flag[cur] = 0;        for(int i = 1; i <= N; i++){            if(dist[cur][i] == -1) continue;            len[i] = minNum(len[i], dist[cur][i] + len[cur]);        }    }}int main(){    int N,M,S,T;    while(cin>>N>>M>>S>>T){        for(int i = 0; i <= N; i++){            for(int j = 0; j <= N; j++){                dist[i][j] = -1;                if(i == j){                    dist[i][j] = 0;                }            }            flag[i] = -1;//初始化为-1表示未知            len[i] = -1; //初始化距离为-1 表示无穷大        }        int x, y , d;        for(int i = 0; i < M; i++){            cin>>x>>y>>d;            dist[x][y] = minNum(dist[x][y], d);            dist[y][x] = dist[x][y]; //无向图,有向图的话,去掉这行代码        }        dijkstra(dist, N, S);        cout<<len[T]<<endl;    }    return 0;}

测试数据:
5 23 5 4 //5是节点数量,id 1-5, 23是边数量,5是起点id,4是终点id
1 2 708 //起点到终点 距离
2 3 112
3 4 721
4 5 339
5 4 960
1 5 849
2 5 98
1 4 99
2 4 25
2 1 200
3 1 146
3 2 106
1 4 860
4 1 795
5 4 479
5 4 280
3 4 341
1 4 622
4 2 362
2 3 415
4 1 904
2 1 716 //无向图,但是会出现同样节点,多条路
2 5 575

0 0
原创粉丝点击