图(二)最短路径——Dijkstra算法

图论(二)

实际上按顺序应该先讲深搜和广搜,不过深搜广搜应该都掌握的还可以:这里就用两句经验之谈来进行总结:

深搜:递归遍历当前连通,且未被遍历的结点。一个函数遍历一个节点,到空为止。

广搜:嵌套式遍历当前结点连通的所有未被遍历的结点。一个函数遍历所有结点,每次嵌套遍历到空为止。

本篇将作为考试复习最短路径的第一篇(应该也是最后一篇)文章,主角是能够实现以下功能的算法:

对于邻接矩阵图:初始设无穷为0XFFFFFF的情况下,寻找起点到终点的最短路径长度与最短路径。

没错,Dijkstra算法。

//核心,dijkstra.
void dijstra(int v0) {
        memset(dist, 0xffffff, n);
        int count = 1;
        for (int i = 1; i <= n; i++) {
            if (ljb[v0][i] != 0xffffff) {
                dist[i] = ljb[v0][i];
            }
            else {
                dist[i] = 0xffffff;
            }
        }//起点初始化。
        for (int i = 1; i <= n; i++) {
            solved[i] = false;
            path[i] = -1;
        }                                   //solve初始化。
        solved[v0] = true;                  //起点已经解决。
        for (int i = 1; i <= n; i++) {      //进行n次。
            int mind = 0xffffff;   //找最小距离
            int j = 0;
            int p = 0;
            for (j = 1; j <= n; j++) { //找新赋值的里最小的一个
                if (!solved[j] && dist[j] < mind) {
                    mind = dist[j];
                    p = j;
                }
            }
            if (count == 1) {
                path[j - 1] = v0;
                count++;
            }
            solved[p] = true; //找到则完成任务,以j为起点开始。
            if (p == 0) {
                return;
            }
            int w = firstadj(p);    //修改直接后继点

            while (w != 0) {
                if (dist[w] > dist[p] + ljb[p][w]) {//小了就改。
                    dist[w] = dist[p] + ljb[p][w];
                    path[w] = p;
                }
                w = nextadj(p, w);
            }//执行完成后,结束。
        }
    }
    //路径
    void print_path() {
    cout << "遍历起点是?" << endl;
    int v0 = 0;
    cin >> v0;
    cout << "遍历终点是?" << endl;
    int ed = 0;
    cin >> ed;
    dijstra(v0);
    cout << dist[ed] << endl;
    int p = ed;
    while (p != v0 && p > 0) {
        cout << p << "->";
        p = path[p];
    }
    cout <<v0 << endl;
}
//邻接矩阵建图
graph() {
       for (int i = 0; i < 100; i++) {
           for (int j = 0; j <= 100; j++) {
               ljb[i][j] = 0xffffff;
           }
       }

       cout << "请输入图的边数n:" << endl;
       cin >> n;
       memset(visited, false, n + 1);
       cout << "请输入对应的边,及对应权值:" << endl;
       for (int i = 1; i <= n; i++) {
           int m = 0, n1 = 0, v = 0;
           cin >> m >> n1 >> v;
           ljb[m][n1] = v;
           ljb[n1][m] = v;
       }
   }

首先,我想说明的是,Dijkstra算法是算连通图两点之间最短路径的,确定的是起点,到各个点的长度,而非任意两点,本质上是一种高级贪心(区别于永远选当前最短的那种低级贪心。)其中利用了广度优先搜索,遍历图的路径,每遍历一次,进行一次筛选,确定出最短路的一个顶点。

那么,接下来是重中之重:Dijkstra算法如何理解,记忆?其实分为四个点:

  1. 函数组成,哪些变量?
  2. 功能实现,哪些模块?
  3. 具体记忆,如何进行初始化?
  4. 具体记忆,如何对数据进行修改?

首先,Dijkstra算法由一个Visted数组(在本篇给的案例中为Solved数组)一个Dist数组,一个图,结点数变量,总起点变量,循环起点变量,中间变量,求邻接点的两个函数,最小变量这些“零件”组成。

模块有初始化数组模块,赋值Dist模块。Dist模块中又分为寻求当前起点模块,广搜模块。而此模块重要的特征是本身基于一个n重循环。

初始化,对于用邻接矩阵表示图的情况来讲,不连通点的初值必须为无限大:0XFFFFFF,否则,会出现混乱,同样,在寻求当前起点模块,最小值初值最好也与邻接表中不连通的点一致。至于Visted数组,自然除起点外全设为false。

最后对数据进行修改,主要记忆,在广搜模块,当存在邻接点时,一直持续筛选,将邻接点的现有距离(该点Dist数组中数据)与当前确定最小距离(本轮起点的Dist)加上邻接路径长度作比,取小的对Dist数组进行修改。选取当前起点时,则注意,应选择未被访问且当前Dist距离最短的点。

本算法对于路径的存储,选择了拉火车式存储,主要利用了数组的性质a[1]=2,a[2]=3,可以用:<1,<2>,3>来表示,意为先走1结点,再来2结点,最后再到3结点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值