【Dijkstra】最短路径

复习笔记【一】 Dijkstra算法

算法核心:对边的松弛 

概述:Dijkstra用于求一个点到其他点的最短路径,不适合于负边权,用了贪心思想,复杂度为O(N^2),  与SPFA相比其优点是经堆优化后Dijkstra的时间复杂度为O(NlogN),和最小生成树Prim算法长的很像...

理解:假设我们要计算从一号点出发,一号点到其他点的最短路径。首先,定义一个一维数组distance,distance[J]表示从1号点到J号点的初始路程,假如说两点之间没有边,那我们就假设其两点间的初始路程为正无穷,因为两点可能永远无法到达~

此时distance中存储了一号点到各顶点的距离(假如说有边的话就是边权, 没边就是正无穷)

假如说对于如下数据:

4 4  //四个顶点四条边

1 2 3

1 3 6

2 3 1

2 4 2

distance[i] i = 1 i = 2 i = 3 i = 4
value 0 3 6 无穷大

显然,其到自身的距离为0。

1号点与2号点间有边相连,其边权为3

同理:distance[1][3] = 6

Edge[1][4]不存在, distance[1][4] = 正无穷

 

此时选取其中最小的distance, 这就是1号结点到被选取的这个点的最短路径了,

distance[2] = 3,所以 到 2号结点的最短距离为3, 因为不可能通过第二条边来让其到1号结点的距离更近(仔细想..)

此时再遍历与2号结点相连的边,如果1号结点到k号结点的距离 > 1号结点的距离到2号结点的距离 + 2号结点到k号结点的距离就更新distance,再然后,选取distance中最小的(可以用堆优化的地方),再以最小的点进行遍历....

 

总结

1.初始化distance数组和标记数组

for (int i = 1; i <= n; i++) {
    distance[i] = edge[1][i];     //edge[1][I]为邻接矩阵存储方式 
    flag[i] = false;            //表示i号结点是否已经被标记为最短路,防止重复遍历 
}
flag[1] = true; 

2.核心语句

for (int i = 1, min, u; i <= n - 1; i++) {
    min = 0x7fffffff;
    for (int j = 1; j <= n; j++) {
        if (!flag[[j] && distance[j] < min) {
            min = distance[j];    //选取最小的distance 
            u = j;
        }
    }
    flag[u] = true;
    for (int k = 1; k <= n; k++) {
        //如果有边 
        if (edge[u][v] < 0x7fffffff) {
            if (distance[v] > distance[u] + edge[u][v]) {
                distance[v] = distance[u] + edge[u][v]
            }
        }
    }
}

for (int i = 1; i <= n; i++) {
    printf ("%d ", distance[i]);
}

 

完整代码

#include <cstdio>
#include <queue>
#include <limits.h>
#define maxn 1005


struct Node {
    int diktc; bool visited;
    struct Edge* edges;
    bool operator () (const Node *a, const Node *b) {
        return a->diktc > b->diktc;
    }
    Node () : diktc (INT_MAX) , visited (false) {}
} nodes[maxn];

struct Edge {
    int weight;
    Node* to;
    Edge* next;
    Edge () {}
    Edge (int w, Node* t) : weight (w), to(t) {}
};

inline void EdgeMaker (const int &u, const int &v, const int &w) {
    Edge* curEdge = new Edge(w, nodes + v);
    curEdge->next = nodes[u].edges;
    nodes[u].edges = curEdge;
}

inline void EdgeDestory (const int& n) {
    for (int i = 0; i < n; i++) {
        Edge* curEdge = nodes[i].edges;
        while (curEdge != NULL) {
            Edge* tmp = curEdge;
            curEdge = curEdge->next;
            delete[] tmp;
        }
    }
}

int n, m;

inline void Dijkstra (const int &start) {
    std::priority_queue<Node*, std::vector<Node*>, Node > pq;
    Edge *curEdge = nodes[start].edges;
    while (curEdge != NULL) {
        curEdge->to->diktc = curEdge->weight;
        pq.push (curEdge->to);
        curEdge = curEdge->next;
    }
    nodes[start].diktc = 0;
    nodes[start].visited = true;
    
    
    
    for (int i = 0; i < n; i++) {
        pq.push (nodes + i);
    }
    
    for (int i = 0, u; i < n - 1; i++) {
        while (pq.top()->visited) {
            pq.pop();
        }
        u = pq.top() - nodes;
        pq.pop();
        nodes[u].visited = true;
        curEdge = nodes[u].edges;
        while (curEdge != NULL) {
            if (curEdge->to->diktc > nodes[u].diktc + curEdge->weight) {
                curEdge->to->diktc = nodes[u].diktc + curEdge->weight;
                pq.push (curEdge->to);
            }
            curEdge = curEdge->next;
        }
    }
    
    for (int i = 1; i <= n; i++) {
        printf ("%d ", nodes[i].diktc);
    }
    printf ("\n");
}


int main () {
    scanf("%d %d", &n, &m);
    for (int i = 0, u, v, w; i < m; i++) {
        scanf ("%d %d %d", &u, &v, &w);
        EdgeMaker (u, v, w);
    //    EdgeMaker (v, u, w);
    }
    Dijkstra (1);
    EdgeDestory (n);
    return 0;
    
}

 

posted @ 2016-07-28 21:59  UEdge  阅读(255)  评论(0)    收藏  举报