<图>Dijkstra

从A开始先把每一个顶点关联的边(未被标记)计算出来(顺便更新路径),关联顶点(未被标记)入队列
如果这个顶点的所有边计算完毕,该顶点出队列

           1
        B ———— D
     5/ |    / | \6
    A  2|  /4  |  F
     1\ | /    |3
        C ———— E
            8
初始化顶点信息表(邻接矩阵):

    city name: A  B  C  D  E  F
    val_2_A  : 0  ∞  ∞  ∞  ∞  ∞
    last_city:-1 -1 -1 -1 -1 -1
    visite   : 0  0  0  0  0  0
起点先入队列:
    — — — — — —
    A
    — — — — — —
A关联B、C,计算AB = 5,AC = 1,AB < AC --> C入队列:
    — — — — — —
    A C
    — — — — — —
更新C:AC=1, last_city=A
    city name: A  B C
    min_2_A  : 0    1
    last_city: φ    A
    visited  :

B入队列:
    — — — — — —
    A C B
    — — — — — —
更新B:AB=5, last_city=A
    city_name: A B C
    min_2_A  : 0 5 1
    last_city: φ A A
    visited  :

A出队列,标记ABC:
    — — — — — —
    C B
    — — — — — —
C关联B、D、E,计算CB = 2,CD = 4 CE = 8 ,CD < CE,D入队列:
    — — — — — —
    C B D
    — — — — — —
再更新B:AB > AC+CB=3,AB=3 ,last_city=C
    city_name: A B C
    min_2_A  : 0 3 1
    last_city: φ C A
    visited  :

更新D:AD=AC+CD=5,last_city=C
    city_name: A B C D
    min_2_A  : 0 3 1 5
    last_city: φ C A C
    visited  :

E入队列:
    — — — — — —
    C B D E
    — — — — — —
更新E:AE = 9,last_city=C
    city_name: A B C D E
    min_2_A  : 0 3 1 5 9
    last_city: φ C A C C
    visited  :


C出队列:
    — — — — — —
        B D E
    — — — — — —
B关联D,但是D已经入队列
更新D:BD=1,AD > AB+BD=4,AD=4,last_city=B
    city name: A B C D E
    min_2_A  : 0 3 1 4 9
    last city: φ C A B C
    visited  :

B出队列:
    — — — — — —
          D E
    — — — — — —
D关联E、F,F入队列
    — — — — — —
          D E F
    — — — — — —
再更新E:DE = 3,AE > AD+DE=7,AE=7,last_city=D
    city name: A B C D E
    min_2_A  : 0 3 1 4 7
    last city: φ C A B D
    visited  :

更新F:DF = 6,AF=AD+DF,last_city=D
    city name: A B C D E F
    min_2_A  : 0 3 1 4 7 10
    last city: φ C A B D D
    visited  :

D关联的边计算完了出队列:
    — — — — — —
            E F
    — — — — — —
E、F关联的边计算完了出队列:
    — — — — — —

    — — — — — —
结果:
    A到F的最短距离为:10
    逆推得到A到F的最短路径:
    F的上一站是D,D的上一站是B,B的上一站是C,C的上一站是A
    F ← D ← B ← C ← A

           1
        B ———— D
     5/ |    / | \6
    A  2|  /4  |  F
     1\ | /    |3
        C ———— E
            8
#include"Dijkstra.h"

// 检验输入边数和顶点数的值是否有效,可以自己推算为啥:
// 顶点数和边数的关系是:((Vexnum*(Vexnum - 1)) / 2) < edge
bool check(int Vexnum, int edge)
{
    if (Vexnum <= 0 || edge <= 0 || ((Vexnum*(Vexnum - 1)) / 2) < edge)
        return false;
    return true;
}
int main()
{
    int vexnum; int edge;

    cout << "输入图的顶点个数和边的条数:" << endl;
    cin >> vexnum >> edge;
    while (!check(vexnum, edge))
    {
        cout << "输入的数值不合法,请重新输入" << endl;
        cin >> vexnum >> edge;
    }

    Graph_DG graph(vexnum, edge);
    graph.createGraph();
    graph.print();
    graph.Dijkstra(1);
    graph.print_path(1);
    system("pause");
    return 0;
}

/*
输入:
6 8
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 6 60
5 4 20

6 8
1 2 5
1 3 1
2 3 2
2 4 1
3 4 4
3 5 8
4 5 3
4 6 6


*/

Dijkstra.cpp

#include"Dijkstra.h"

int INT_MAX = 100000;

//构造函数,
Graph_DG::Graph_DG(int vexnum, int edge)
{
    //初始化顶点数和边数
    this->vexnum = vexnum;
    this->edge = edge;
    //为二维邻接矩阵开辟空间和赋初值
    arc = new int* [this->vexnum];
    // 一维数组,每个元素代表一个顶点指针
    dis = new Dis[this->vexnum];
    for (int i = 0; i < this->vexnum; i++)
    {
        arc[i] = new int[this->vexnum];
        for (int k = 0; k < this->vexnum; k++) {
            //邻接矩阵初始化为无穷大
                arc[i][k] = INT_MAX;
        }
    }
}
//析构函数
Graph_DG::~Graph_DG() {
    delete[] dis;
    for (int i = 0; i < this->vexnum; i++) {
        delete this->arc[i];
    }
    delete arc;
}

// 判断我们每次输入的的边的信息是否合法
//顶点从1开始编号
bool Graph_DG::check_edge_value(int start, int end, int weight) {
    if (start<1 || end<1 || start>vexnum || end>vexnum || weight < 0) {
        return false;
    }
    return true;
}

void Graph_DG::createGraph() {
    cout << "请输入每条边的起点和终点(顶点编号从1开始)以及其权重" << endl;
    int start;
    int end;
    int weight;
    int count = 0;
    while (count != this->edge)
    {
        cin >> start >> end >> weight;
        //首先判断边的信息是否合法
        while (!this->check_edge_value(start, end, weight))
        {
            cout << "输入的边的信息不合法,请重新输入" << endl;
            cin >> start >> end >> weight;
        }
        //对邻接矩阵对应上的点赋值
        arc[start - 1][end - 1] = weight;
        //无向图添加上这行代码
        //arc[end - 1][start - 1] = weight;
        ++count;
    }
}

void Graph_DG::print() {
    cout << "图的邻接矩阵为:" << endl;
    int count_row = 0; //打印行的标签
    int count_col = 0; //打印列的标签
    //开始打印
    while (count_row != this->vexnum) {
        count_col = 0;
        while (count_col != this->vexnum) {
            if (arc[count_row][count_col] == INT_MAX)
                cout << "∞" << " ";
            else
            cout << arc[count_row][count_col] << " ";
            ++count_col;
        }
        cout << endl;
        ++count_row;
    }
}

/*
	 A B C D E F
A	{0,5,1,X,X,X},
B	{5,0,2,1,X,X},
C	{1,2,0,4,8,X},
D	{X,1,4,0,3,6},
E	{X,X,8,3,0,X},
F	{X,X,X,6,X,0},

 */
void Graph_DG::Dijkstra(int begin)
{
    //首先初始化我们的dis数组
    int i;
    for (i = 0; i < this->vexnum; i++)
    {
        //设置当前的路径
        dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1);
        dis[i].value = arc[begin - 1][i];
    }
    //设置起点的到起点的路径为0
    dis[begin - 1].value = 0;
    dis[begin - 1].visit = true;

    int count = 1;
    //计算剩余的顶点的最短路径(剩余this->vexnum-1个顶点)
    while (count != this->vexnum)
    {
        //temp用于保存当前dis数组中最小的那个下标
        //min记录的当前的最小值
        int temp=0;
        int min = INT_MAX;
        for (i = 0; i < this->vexnum; i++)
        {
            if (!dis[i].visit && dis[i].value<min)
            {
                min = dis[i].value;
                temp = i;
            }
        }
        //cout << temp + 1 << "  "<<min << endl;
        //把temp对应的顶点加入到已经找到的最短路径的集合中
        dis[temp].visit = true;
        ++count;
        for (i = 0; i < this->vexnum; i++)
        {
            //注意这里的条件arc[temp][i]!=INT_MAX必须加,不然会出现溢出,从而造成程序异常
            if (!dis[i].visit && arc[temp][i]!=INT_MAX && (dis[temp].value + arc[temp][i]) < dis[i].value)
            {
                //如果新得到的边可以影响其他为访问的顶点,那就就更新它的最短路径和长度
                dis[i].value = dis[temp].value + arc[temp][i];
                dis[i].path = dis[temp].path + "-->v" + to_string(i + 1);
            }
        }
    }

}

void Graph_DG::print_path(int begin)
{
    string str;
    str = "v" + to_string(begin);
    cout << "以"<<str<<"为起点的图的最短路径为:" << endl;
    for (int i = 0; i != this->vexnum; i++) {
        if(dis[i].value!=INT_MAX)
        cout << dis[i].path << "=" << dis[i].value << endl;
        else {
            cout << dis[i].path << "是无最短路径的" << endl;
        }
    }
}

Dijkstra.h

#pragma once
//#pragma once是一个比较常用的C/C++杂注,
//只要在头文件的最开始加入这条杂注,
//就能够保证头文件只被编译一次。

#include<iostream>
#include<string>
using namespace std;

/*
本程序是使用Dijkstra算法实现求解最短路径的问题
采用的邻接矩阵来存储图
*/
//记录起点到每个顶点的最短路径的信息
struct Dis
{
    string path;
    int value;// 边长
    bool visit;
    // 构造函数
    Dis()
    {
        visit = false;
        value = 0;
        path = "";
    }
};

class Graph_DG
{
private:
    int vexnum;   //图的顶点个数
    int edge;     //图的边数
    int **arc;   //邻接矩阵
    Dis* dis;   //记录各个顶点最短路径的信息
public:
    //构造函数
    Graph_DG(int vexnum, int edge);
    //析构函数
    ~Graph_DG();
    // 判断我们每次输入的的边的信息是否合法
    //顶点从1开始编号
    bool check_edge_value(int start, int end, int weight);
    //创建图
    void createGraph();
    //打印邻接矩阵
    void print();
    //求最短路径
    void Dijkstra(int begin);
    //打印最短路径
    void print_path(int);
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值