最短路径(Dijkstra算法)

Dijkstra算法核心思想:
求起始点到达某一点的最短距离,所有点被分为两个集合,已确定最短路径长度的顶点集合S和未知最短距离顶点集合V-S。用dist[j]表示点j到达起始点的最短距离,借助中间点t,可能起始点与点j的直接距离大于借助中间点t的间接距离,此处需要加以判断,同时需要更新dist[j];此外需要借助pre[max]数组存中间点t,方便寻找最短路径具体过程。

核心步骤:初始化—>寻找距离中间点t的最短距离—>将距离最短的点t加入集合S—>更新最短距离—>记录中间点t的路径存在pre[max]

动画效果演示:Dijkstra算法

算法具体实现

#include 

using namespace std;

const int maxx=1e3;  //点的数量的最大取值
const int inf=0x3f3f3f3f;
int mp[maxx][maxx];  //记录每条边的权值信息
int flag[maxx];  //标记该点是否加入集合S中
int dist[maxx];  //表示该点与起始点的最短距离
int pre[maxx];  //记录该点的前驱结点,从而记录最短路径过程
int n,m,u,v,w;

void Dijkstra(int u){  //设起始点为u
    for(int i=1;i<=n;i++){  //进行初始化
		dist[i]=mp[u][i]; //初始状态设各个点到达起始点的最短距离为mp[u][i]
		flag[i]=0;  //初始状态未选择任何点,集合S为空集
		if(dist[i]==inf) //点i与起始点没有直接路径
			pre[i]=-1;
		else
			pre[i]=u; //点i与起始点直接相连,则点i的前驱结点为起始点u
	}
    dist[u]=0;  //点u到达起始点u自身距离为0
    flag[u]=1;  //将起始点u加入集合S
    for(int i=1;i<=n;i++){
        int temp=inf,t=u; //temp为中间变量,用于寻找最短距离dist[j];t是连接起始点u到达点j的中间点
        for(int j=1;j<=n;j++){
            if(!flag[j]&&dist[j]<temp){
                temp=dist[j]; //找到最短距离
                t=j;  //记录中间结点t
            }
        }
        if(t==u) return; //找不到t直接退出
        flag[t]=1;  //将中间点t加入集合S
        for(int j=1;j<=n;j++){ //更新点j到达起始点的最短距离
            if(!flag[j]&&mp[t][j]<inf){
                if(dist[j]>dist[t]+mp[t][j]){
                    dist[j]=dist[t]+mp[t][j];
                    pre[j]=t;  //将点t存入pre数组
                }
            }
        }
    }
}

//用于返回起始点到达某个点i的路径过程
void findpath(int u){
    int x;
    stack<int>s; //返回中间点t的过程是逆过程,采用栈进行存储
    for(int i=1;i<=n;i++){
        x=pre[i]; //设x为u->i路径中点i的前驱结点
        while(x!=-1){
            s.push(x); //将前驱结点x依次压入栈中
            x=pre[x];
        }
        while(!s.empty()){ //若栈非空,则依次弹出栈内的中间点
            cout<<s.top()<<"->"; //获取栈顶元素,此时栈顶元素未被删除
            s.pop();  //删除栈顶元素
        }
        cout<<i<<";最短距离为:"<<dist[i]<<endl; //最后输出终点i,以及u->i的最短距离
    }
}

int main()
{
    int u,v,w,st;
    cin>>n>>m;
    memset(mp,inf,sizeof(mp));  //初始化数组边的权值
    memset(dist,inf,sizeof(dist)); //初始化各个点到达起始点的最短路径
    for(int i=1;i<=m;i++){
        cin>>u>>v>>w;   //依次输入边的权值信息
        mp[u][v]=min(mp[u][v],w);
    }
    cin>>st; //输入起始点
    Dijkstra(st); //获得st->j路径的最短距离
    findpath(st); //返回该路径全过程
    return 0;
}

样例测试
输入:
城市个数n,道路数量m

5 11

请输入城市之间的路线以及距离

1 5 2
5 1 8
1 2 16
2 1 29
5 2 32
2 4 13
4 2 27
1 3 15
3 1 21
3 4 7
4 3 19

输入起始位置st:

5

输出:

5->1;最短距离为:8
5->1->2;最短距离为:24
5->1->3;最短距离为:23
5->1->3->4;最短距离为:30
5;最短距离为:0

希望对你有所帮助!

你可能感兴趣的:(数据结构,最短路径dijkstra)