• 迪杰斯特拉算法


    迪杰斯特拉(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
    ",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
    ",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
    ",dist[n]);
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    HTTP协议抓包分析
    cmd 中使用 tracert
    Ubuntu 搭建zabbix
    kerberos+ldap
    运行程序显示丢失“MSVCR100D.dll”
    熊猫烧香病毒样本分析
    Masm32sdk安装指南
    16位汇编实现三大基本排序
    逆向工程初步160个crackme-------3
    一个入门级CTF的Reverse
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11239588.html
Copyright © 2020-2023  润新知