【算法】Dijkstra算法

前言

  已经有一段时间没有更新博客了,主要是因为变得比较忙了,什么高数啊大物啊期中考试都来了,也就没时间写代码了。最近还参加了一个大创的项目,也在忙着修改着项目申报表。

  现在我可是深刻感受到了:专业选得好,年年赛高考啊。

  今天来写一下Dijkstra算法,可是想到还有之前的Prim算法,关键路径算法,Kruskal算法还有后面的平衡排序树,B树的修复,哎呀我滴娘嘞,怎么能这么多嘞!

 

算法思想

  Dijkstra算法主要用于图中求一个固定点到其余各个顶点的最短路径。

  算法需要引入几个辅助数组。

  • \(S\):表示已经找到最短路径的顶点的集合
  • $dist$:辅助数组,$dist[i]$表示目前已找到的从开始点$v_{0}$到终点$v_{i}$的当前最短路径
  • $path$:$path[i]$表示从$v_{0}$到$v_{i}$的最短路径需要经过依次经过的结点。

  大概的步骤如下:

  • 初始化,加入以$1$为开始点,则$dist[i]$初始化为从$v_{1}$到$v_{i}$的路径长度(权值)
  • 从$dist$中找出距离最短的,将其加入$S$
  • 修正从$v_{0}$出发到顶点集合$V-S$($V$表示全集)上任意顶点的路径长度。
  • 重复上述过程,即可求出按最短路径长度递增顺序排列的数组$S$.

  其中修正过程如下:

  1. 从$v_{0}$出发,到集合$V-S$上任一顶点$v_{i}$的当前最短路径长度为$dist[i]$
  2. 从$v_{0}$出发,中间经过了新加入S中的顶点$v_{k}$,然后到达集合$V-S$上任一顶点$v_{i}$路径长度为$dist[k]+g.arcs[k][j]$.如果$dist[k]+g.arcs[k][j] < dist[i]$,则$dist[i] = dist[k]+g.arcs[k][j]$

实现

关键代码

void Graph::dijkstra()
{
    for (  int i = 2; i <= vernum - 1; i++)
    {
        int min = 32767, k;
        for (  int j = 1; j < vernum; j++)
        {
            if (!dist[j].hasFound && dist[j].data < min)
            {
                k = j;
                min = dist[j].data;
            }
        }
        if (min == 32767)
        {
            return ;
        }
        dist[k].hasFound =   true ;
        for (  int j = 0; j < vernum; j++)
        {
            if (!dist[j].hasFound && arc[k][j] != 32767 && dist[k].data + arc[k][j] < dist[j].data)
            {
                dist[j].data = dist[k].data + arc[k][j];
            }
        }
    }
}

具体过程在算法思路里已经详尽得给出,不过这里并没有用到path。

解题

下面为NOJ第22题的代码,这里使用一个$bool$值来判定是否在$S$中。

/*
 * @Author: zh(RickSchanze)(帝皇の惊)
 * @Description: Dijkstra算法
 * @Date: 2022-05-09 23:14:54
 * @LastEditTime: 2022-05-14 20:12:37
 */
#include 
#include 

struct Isfound
{
    int data = 32767;
    bool hasFound =   false ;
};

struct Graph
{
    int vertex[100] = {0};
    int arc[100][100];
    int vernum = 0;
    int arcnum = 0;
    Isfound dist[100];
    void createGraph();
    void dijkstra();
    void print();
};

void Graph::print()
{
    struct temp
    {
        int index;
        int data;
    };
    temp t[100];
    for (  int i = 2; i <= vernum; i++)
    {
        t[i].index = i;
        t[i].data = dist[i].data;
    }
    std::sort(&t[2], &t[vernum], [](temp a, temp b)
              {   return a.data < b.data; });
    for (  int i = 2; i <= vernum; i++)
    {
        if (t[i].data == 32767)
        {
            std::cout <<   "1"
                      <<   " " << t[i].index <<   " "
                      <<   "-1" << std::endl;
            continue ;
        }
        std::cout <<   "1"
                  <<   " " << t[i].index
                  <<   " " << t[i].data << std::endl;
    }
}
void Graph::createGraph()
{
    std::cin >> vernum >> arcnum;
    for (  int i = 1; i <= vernum; i++)
    {
        vertex[i] = i;
    }

    for (  int i = 1; i <= arcnum; i++)
    {
        for (  int j = 1; j <= arcnum; j++)
        {
            arc[i][j] = 32767;
        }
    }

    for (  int i = 0; i < arcnum; i++)
    {
        int first, end;
        std::cin >> first >> end;
        std::cin >> arc[first][end];
    }

    for (  int i = 2; i <= vernum; i++)
    {
        dist[i].data = arc[1][i];
    }
}

void Graph::dijkstra()
{
    for (  int i = 2; i <= vernum - 1; i++)
    {
        int min = 32767, k;
        for (  int j = 1; j < vernum; j++)
        {
            if (!dist[j].hasFound && dist[j].data < min)
            {
                k = j;
                min = dist[j].data;
            }
        }
        if (min == 32767)
        {
            return ;
        }
        dist[k].hasFound =   true ;
        for (  int j = 0; j < vernum; j++)
        {
            if (!dist[j].hasFound && arc[k][j] != 32767 && dist[k].data + arc[k][j] < dist[j].data)
            {
                dist[j].data = dist[k].data + arc[k][j];
            }
        }
    }
}

int main()
{
    Graph aGraph;
    aGraph.createGraph();
    aGraph.dijkstra();
    aGraph.print();
    return 0;
}

  

 

posted @ 2022-05-14 20:49  帝皇の惊  阅读(187)  评论(0)    收藏  举报