迪杰斯特拉算法

迪杰斯特拉(Dijkstra)算法是最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心一层一层的向外走(广度优先搜索),直到找到终点

先看具体的例子来体会下它的算法思想:

 

 

 

    • dist[]:起点到未被并入的顶点的最短距离
      【类比】Prim算法中的lowCost[]:当前生成树到为并入的顶点的最短距离
    • path[]:起点到该顶点的最短路径
    • S[]:已并入的顶点

 

步骤

【第一步】

 

【第二步】

 

 

【步骤三】

 

 

【步骤四】

 

 

 

【步骤五】 

 

 

【步骤六】

 

 

 

【算法结束】

  1. dist[v]:起点0到v的最短路径长度
  2. path[v]:起点0到v的最短路径

 

 

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <stdbool.h>
 5 #include <stdlib.h>
 6 #include <stack>
 7 
 8 #define INF 0x3f3f3f3f
 9 using namespace std;
10 const int MAXN = 10005;
11 
12 int graph[MAXN][MAXN];
13 int dist[MAXN];
14 bool vis[MAXN];
15 int pre[MAXN];
16 int n,m;
17 
18 stack<int> path;
19 
20 void dijistra(int x){
21     int pos = x;
22     memset(pre,-1, sizeof(pre));
23     for(int i = 1; i <= n; i ++){
24         dist[i] = graph[pos][i];
25     }
26     vis[pos] = true;
27     for(int i = 1; i <= n; i ++){
28         int mins = INF;
29         for(int j = 1; j <= n; j ++){
30             if(!vis[j] && dist[j] < mins){
31                 pos = j;
32                 mins = dist[j];
33             }
34         }
35         vis[pos] = true;
36         for(int j = 1; j <= n; j ++){
37             if(!vis[j] && dist[j] > dist[pos] + graph[pos][j]){
38                 dist[j] = dist[pos] + graph[pos][j];
39                 pre[j] = pos;
40             }
41         }
42     }
43 }
44 
45 int main()
46 {
47     freopen("../in.txt","r",stdin);
48     int T;
49     scanf("%d",&T);
50     while (T--)
51     {
52         scanf("%d%d",&n,&m);
53         for (int i=1;i<=n;i++)
54         {
55             for (int j=1;j<=n;j++)
56             {
57                 if (i == j)
58                     graph[i][j] = 0;
59                 else
60                     graph[i][j] = INF;
61             }
62         }
63         for (int i=1;i<=m;i++)
64         {
65             int a,b,c;
66             scanf("%d%d%d",&a,&b,&c);
67             graph[a][b] = graph[b][a] = c;
68         }
69 
70         int start,end;
71         scanf("%d%d",&start,&end);
72         memset(vis, false, sizeof(vis));
73         dijistra(start);
74         int temp = end;
75         while (pre[temp]!=-1)
76         {
77             path.push(temp);
78             temp = pre[temp];
79         }
80         path.push(temp);
81         cout << "path: " << start << " ";
82         while (!path.empty())
83         {
84             printf("%d ",path.top());
85             path.pop();
86         }
87         cout << endl;
88         cout << "distance:" << endl;
89         printf("%d\n",dist[end]);
90     }
91     return 0;
92 }

 

上面的是数组的写法,但是有的时候题目的数据量太大往往会导致数组的写法不能够使用。

因为不能够开这么大的数组,嘤嘤嘤

 

所以现在重点来了,我们使用邻接矩阵的写法并且采取优先队列的方式对我们Dj算法进行优化:

 

模版题: poj1511:http://poj.org/problem?id=1511

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <stdbool.h>
  5 #include <stdlib.h>
  6 #include <string>
  7 #include <string.h>
  8 #include <math.h>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <map>
 13 
 14 #define INF 0x3f3f3f3f
 15 #define LL long long
 16 #define MAXN 1000001
 17 using namespace std;
 18 
 19 typedef pair<int,int> P;  //first 是最短距离,second 是编号
 20 struct edge{     // 边
 21     int f;  // 起点
 22     int t;  // 终点
 23     int c;  // 花费
 24     edge(){
 25         f = 0;
 26         t = 0;
 27         c = 0;
 28     }
 29     edge(int ff,int tt,int cc){
 30         f = ff;
 31         t = tt;
 32         c = cc;
 33     }
 34 };
 35 int n,m;
 36 int dist[MAXN];  // 记录距离
 37 vector<edge> graph[MAXN];  // 领接矩阵
 38 edge edges[MAXN];  // 存边的数组
 39 bool vis[MAXN];
 40 
 41 void dijkstra(int x)
 42 {
 43     priority_queue<P,vector<P>,greater<P> > Q;
 44     for (int i=1;i<=n;i++)
 45         dist[i] = INF;
 46     dist[x] = 0;
 47     memset(vis,false, sizeof(vis));
 48     Q.push(P(0,x));
 49     while (!Q.empty())
 50     {
 51         int v = Q.top().second;
 52         Q.pop();
 53         if (vis[v])  //如果更新过
 54             continue;
 55         vis[v] = true;
 56         // 遍历当前点相邻的所有点
 57         for (int i=0;i<graph[v].size();i++)
 58         {
 59             edge e = graph[v][i];
 60             if (dist[e.t]>dist[v]+e.c) //找最短路
 61             {
 62                 dist[e.t] = dist[v] + e.c;
 63                 Q.push(P(dist[e.t],e.t));
 64             }
 65         }
 66     }
 67 }
 68 
 69 void init()
 70 {
 71     for (int i=0;i<=n;i++)
 72         graph[i].clear();
 73 }
 74 
 75 
 76 int main()
 77 {
 78     //freopen("../in.txt","r",stdin);
 79     int T;
 80     scanf("%d",&T);
 81     while (T--)
 82     {
 83         scanf("%d%d",&n,&m);
 84         init();
 85         for (int i=1;i<=m;i++)
 86         {
 87             int a,b,c;
 88             scanf("%d %d %d",&a,&b,&c);
 89             edges[i] = edge(a,b,c);
 90             graph[a].push_back(edge(a,b,c)); // a 为顶点
 91             //graph[b].push_back(edge(b,a,c));  无向图
 92         }
 93         dijkstra(1);
 94         long long int sum = 0;
 95         for (int i=1;i<=n;i++)
 96             sum += dist[i];
 97         init();
 98         for (int i=1;i<=m;i++)
 99         {
100             edge tmp = edges[i];
101             graph[tmp.t].push_back(edge(tmp.t,tmp.f,tmp.c));
102         }
103         dijkstra(1);
104         for (int i=1;i<=n;i++)
105             sum += dist[i];
106         printf("%lld\n",sum);
107     }
108     return 0;
109 }

 

前向星加链式存储加优先队列优化

 1 #include <stdio.h>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <string.h>
 5 #include <stdlib.h>
 6 #include <queue>
 7 
 8 #define INF 0x3f3f3f3f
 9 #define pii pair<int,int>
10 using namespace std;
11 const int MAXN = 2e5+7;
12 
13 int head[MAXN];
14 int dist[MAXN];
15 bool vis[MAXN];
16 int cnt;
17 
18 struct Edge{
19     int to,val,next;
20 }edge[MAXN];
21 
22 void init(){
23     cnt = 0;
24     memset(head,-1, sizeof(head));
25     memset(vis,false, sizeof(vis));
26     memset(dist,INF, sizeof(dist));
27 }
28 
29 void add(int u,int v,int w){
30     edge[cnt].to = v;
31     edge[cnt].val = w;
32     edge[cnt].next = head[u];
33     head[u] = cnt++;
34 }
35 
36 void dijstra(int s)
37 {
38     priority_queue<pii,vector<pii>,greater<pii> > q;
39     dist[s] = 0;
40     q.push({dist[s],s});
41     while (!q.empty())
42     {
43         int now = q.top().second;
44         q.pop();
45         if (vis[now])
46             continue;
47         vis[now] = true;
48         for (int i=head[now];i!=-1;i=edge[i].next)
49         {
50             int v = edge[i].to;
51             if (dist[v]>dist[now]+edge[i].val)
52             {
53                 dist[v] = dist[now] + edge[i].val;
54                 q.push({dist[v],v});
55             }
56         }
57     }
58 }
59 
60 int main()
61 {
62     int n,m,s;
63     while (~scanf("%d%d",&n,&m))
64     {
65         init();
66         while (m--)
67         {
68             int a,b,c;
69             scanf("%d%d%d",&a,&b,&c);
70             add(a,b,c);
71         }
72         dijstra(1);
73         printf("%d\n",dist[n]);
74     }
75     return 0;
76 }

 

posted @ 2019-07-24 17:33  _Ackerman  阅读(4315)  评论(1编辑  收藏  举报