Dijkstra最短路径(贪心算法)

算法思想:
    令G = (V,E)为一个带权有向图, 把图中的顶点集合V分成两组,第一组为已求出最短路径的顶点集合S(初始时S中只有源节点,以后每求得一条最短路径,就将它对应的顶点加入到集合S中,直到全部顶点都加入到S中 );第二组是未确定最短路径的顶点集合U。在加入过程中,总保持从源节点v到S中各顶点的最短路径长度不大于从源节点v到U中任何顶点的最短路径长度。

算法步骤:
    (1)初始化时,S只含有源节点;
    (2)从U中选取一个距离v最小的顶点k加入S中(该选定的距离就是v到k的最短路径长度 );
    (3)以k为新考虑的中间点,修改U中各顶点的距离;若从源节点v到顶点u的距离(经过顶点k )比原来距离(不经过顶点k )短,则修改顶点u的距离值,修改后的距离值是顶点k的距离加上k到u的距离;
    (4)重复步骤(2)和(3),直到所有顶点都包含在S中。


代码实例:
#include <iostream>
#include <string>
#include <sstream>


using namespace std;


struct Dis{					// 对于集合 V(G) 内每一个元素构建结构体 
    string path;			// 路径 
    int value;				// 权值 
    bool visit; 
    Dis()
    {
        visit = false;
        value = 0;
        path = "";
    }
};


string to_string(int n)			// int 类型转 string 类型 
{
    ostringstream stream;
    stream << n;
    return stream.str();
}

class Graph{
private:
    int vexnum;			// 顶点数目 
    int edge;			// 边数 
    int **arc;			// 邻接矩阵 
    Dis *dis;
public:
    Graph(int vexnum,int edge);		//邻接矩阵法创建图 
    ~Graph();
    bool check_edge_value(int start, int end, int weight);  // 检查待插入元素位置是否正确
    void createGraph();             // 向邻接矩阵中输入数据 
    void print();                   // 打印图
    void Dijkstra(int begin);       // 最短路径算法
    void print_path(int number);          // 输出最短路径
};


Graph::Graph(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::~Graph()
{
    delete[] dis;
    for(int i = 0; i < vexnum; ++i)
        delete arc[i];
    delete arc;
}


bool Graph::check_edge_value(int start, int end, int weight)
{
    if(start < 1 || end < 1 || weight < 0 || start > vexnum || end > vexnum)
        return false;
    return true;
}


void Graph::createGraph()
{
    cout << "input every points start end weight" << endl;
    int start,end,weight,count = 0;
    while(count != edge)
    {
        cin >> start >> end >> weight;
        while(!check_edge_value(start,end,count))
        {
            cout << "input error,please again" << endl;
            cin >> start >> end >>weight;
        }
        arc[start-1][end-1] = weight;
        ++count;
    }
}


void Graph::print()
{
    for(int i = 0; i < vexnum; ++i)
    {
        for(int j = 0; j < vexnum; ++j)
        {
            if(arc[i][j] == INT_MAX)
                cout << "∞ ";
            else
                cout << arc[i][j] << " ";
        }
        cout << endl;
    }
}



// 迪杰特斯拉算法 
void Graph::Dijkstra(int begin)
{
    for(int i = 0; i < vexnum; ++i)
    {
        dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1);
        dis[i].value = arc[begin-1][i];
    }
    dis[begin-1].value = 0;
    dis[begin-1].visit = true;
    dis[begin-1].path = "v"+to_string(begin);
    for(int i = 0; i < vexnum; ++i)
    {
        int temp = 0;
        int min = INT_MAX;
        for(int j = 0; j < vexnum; ++j)		//选取除最短顶点集合外的最短路径 
        {
            if(dis[j].visit == false && dis[j].value < min)
            {
                min = dis[j].value;
                temp = j;
            }
        }
        dis[temp].visit = true;
        for(int k = 0; k < vexnum; ++k)
        {
            if(dis[k].visit == false && arc[temp][k] != INT_MAX && dis[temp].value+arc[temp][k] < dis[k].value) // 算法核心:新加入的点是否能到达其他点,并且通过该点到达目标点的路径是否小于直接到达 
            {
                dis[k].value = dis[temp].value + arc[temp][k];		//更新路径 
                dis[k].path = dis[temp].path+"-->v"+to_string(k+1);		//记录路径 
            }
        }
    }
}


void Graph::print_path(int number)
{
    if(dis[number-1].value == INT_MAX)
        cout << "it can not reach" << endl;
    else
    cout << "path:" << dis[number-1].path;
}


int main(int argc,char **argv)
{
    int start,end,vex,arc;
    cout << "input the number of vex and arc:";
    cin >> vex >> arc;
    Graph g(vex,arc);
    g.createGraph();
    g.print();
    cout << "start:";
    cin >>start;
    g.Dijkstra(start);
    cout << "end:";
    cin >> end;
    g.print_path(end);
    return 0;
}

参考文献:
    [1].程杰.大话数据结构[M].清华大学出版社.2011

猜你喜欢

转载自blog.csdn.net/adorkable_thief/article/details/80171340