贪心策略之Dijkstra算法

Dijkstra算法是解决有向带权图中最短路径的算法。

我用自己的语言解释Dijkstra算法的过程:

1.首先有一个有向带权图G=(V,E),V为顶点集合,E为边集合,用邻接矩阵map[n][n]来储存。

    确定一个起始点origin,有一个辅助集合s,一开始将origin并入s中。

    有一个辅助数组dist[n],dist[i]表示i距离origin的最短距离,初始化dist[i]=map[origin][i]。若不存在弧则相应等于无穷大

2.找一个顶点j,使顶点j存在于V-s中(即顶点j属于V但不属于s),并且dist[j]是所有V-s顶点中最小的一个,将顶点j并入s中;

3.遍历以顶点j为地点的弧<j,k>且k属于V-s中,如果dist[k] > dist[j] + weight<j,k>,则令dist[k]=dist[j] + weight<j,k>;

    这一步相当于搭一个顶点j的顺风车。已知origin-j最短的距离是dist[j],若origin-k的(直接)距离大于

    dist[j] + weight<j,k>,说明源点到顶点k的路径可以通过顶点j这条路而减少距离。

4.重复2,3步,直到s中包含了V中所有的顶点,结束算法。

代码:(C++实现)

#include <iostream>
#define MAX 999999
using namespace std;

const int n =5;          //顶点数量
int map[n+1][n+1];       //有向图 邻接矩阵
int dist[n+1]={MAX};     //起点到其余顶点的距离
int s[n+1]={0};          //顶点集合
int pre[n+1]={0};        //每个顶点的直接前驱


void findMin(int origin)
{
    int i,j;
    for(j=1;j<=n;j++)
    {
        int minWeight=MAX;      //dist[i]中最小权值
        int minPoint =0;        //最小权值的点
        for(i=1;i<=n;i++)
        {
            if( !s[i] && dist[i]<= minWeight ) //寻找不在s中的最小权值的点
            {
                minWeight = dist[i];
                minPoint = i;
            }
        }
        if(minPoint==0)         //如果没有找到,说明所有顶点都以并入s中
            return ;
        s[minPoint]=1;                         //将最小权值的点并中s中
        //修改不在s中的其他顶点的dist值
        for(i=1;i<=n;i++)
        {
            if( !s[i] && map[minPoint][i] != MAX)
                if(dist[i] > dist[minPoint] + map[minPoint][i])
                {
                    dist[i] = dist[minPoint] + map[minPoint][i];
                    pre[i] = minPoint;  //将需要修改的顶点的直接前驱改为最小的权值点
                }
        }
    }

}

void findPath(int i)
{
    if(pre[i]==0)   //表示i可能是起始点,也可能是和起始点不强连通的的点
    {
        if(dist[i] != MAX)  //起始点
            cout<<i;
        else                //与起始点不强连通的点
            cout<<"不存在";
        return ;
    }
    findPath(pre[i]);
    cout<<"-"<<i;

}

int main()
{
    int i,j;
    int weight;
    int origin;              //起点顶点


    //邻接矩阵初始化
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            map[i][j] = MAX;

    cout<<"请输入权值"<<endl;
    cout<<"格式:i j weight"<<endl;
    cout<<"示例:1 2 2  即有一条弧<1,2>,权值为2,未输入数据则默认为无穷大"<<endl;
    cout<<"结束时输入 0 0 0"<<endl;
    cout<<"*************************"<<endl;
    while(1)
    {
        cin>>i>>j>>weight;
        if(i==0 && j==0 && weight==0)
            break;
        else
            map[i][j] = weight;
    }

    cout<<"请输入起始点"<<endl;
    cin>>origin;
    //也可以通过遍历邻接矩阵找到入度为0的点找到源点
    map[origin][origin]=0;

    /*初始化dist[]与pre[]
     *dist[]初始值为源点与其余顶点i的权值,即map[origin][i],不存在弧则为无穷大MAX
     *pre[] 中,若其余顶点i与源点有弧,则pre[i]=1,否则等于0
     */
    for(i=1;i<=n;i++)
    {
        dist[i]=map[origin][i];
        if(map[origin][i] != MAX && map[origin][i] != 0)
            pre[i]=origin;
    }
    s[origin]=1;//初始化s[],即将源点加入s中
    findMin(origin);

    /*输出顶点的顶点的最短路径*/
    for(i=1;i<=n;i++)
    {
        cout<<"从起点"<<origin<<"去顶点"<<i<<"的最短路径为:";
        findPath(i);
        cout<<" 最短距离为:"<<dist[i];
        cout<<endl;
    }

    return 0;
}

实现示例:

例子1:

《贪心策略之Dijkstra算法》

例子2:

《贪心策略之Dijkstra算法》

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/qq_39304201/article/details/79935699
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞