单源最短路径算法

单源最短路径算法

1. 原理

单源最短路径算法是一种用于在有向图或无向图中找到从指定源节点到其他所有节点的最短路径的算法。常用的单源最短路径算法有Dijkstra算法、Floyd-Warshall算法和Bellman-Ford算法。

2. Dijkstra算法

Dijkstra算法是最常用的单源最短路径算法之一,它的基本思想是:从源节点开始,每次选择距离源节点最近的一个未访问过的邻居节点,更新其距离值,直到所有节点都被访问过。

2.1 算法流程

  1. 初始化:将所有节点的距离值设为无穷大,源节点的距离值设为0。创建一个距离数组dist,用于存储每个节点到源节点的距离。同时创建一个访问数组vis,用于标记每个节点是否被访问过。
  2. 选择未访问过的邻居节点中距离最小的节点u。
  3. 将节点u的距离值更新为当前距离值加上u与源节点之间的边权值。
  4. 标记节点u为已访问。
  5. 重复步骤2-4,直到所有节点都被访问过。
  6. 从源节点出发,根据dist数组回溯得到最短路径。

2.2 C++代码实现

#include<bits/stdc++.h>
#define reg register
using namespace std;

// 读取输入的整数,包括正负号和可能的小数部分
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

// 输出整数,包括正负号和小数部分
void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}

const int MAXN=100005,MAXM=200005,INF=(1<<30);
struct node_1{
    int to,dis,next;
};
struct node_2{
    int dis,pos;
    bool operator <(const node_2 &x)const{
        return x.dis<dis;
    }
};
priority_queue<node_2 > q; // 优先队列,用于存储待处理的节点,按照距离从小到大排序
vector<node_1 > edge; // 存储图的边的信息,包括目标节点、距离等信息
int head[MAXN],dis[MAXN],cnt,n,m,s; // n为节点数量,m为边的数量,s为起始节点编号
bool vis[MAXN]; // 标记节点是否已经被访问过

// 添加一条边到图中,参数分别为起点、终点和距离
inline void add_edge(int u, int v, int d){
    edge.push_back((node_1){v,d,head[u]}); // 将终点、距离和头结点的信息存入edge向量中
    head[u]=edge.size()-1; // 将头结点的指针指向当前边的尾部结点的位置
    return ;
}

// Dijkstra算法求解最短路径问题,参数为起始节点编号s和邻接矩阵表示的图edge
inline void dijkstra(){
    dis[s]=0; // 将起始节点的距离设为0,并将其加入优先队列中
    q.push((node_2){0,s}); // 将起始节点的信息存入优先队列中,按照距离从小到大排序
    while(!q.empty()){ // 当优先队列不为空时,循环执行以下操作
        node_2 tmp=q.top(); // 取出队首元素,即当前距离最小的节点及其距离值tmp.dis和位置tmp.pos
        q.pop(); // 将该节点从队列中移除
        int x=tmp.pos,d=tmp.dis; // 将该节点的位置和距离值分别赋给变量x和d
        if(vis[x]) continue; // 如果该节点已经被访问过,则跳过本次循环,继续处理下一个节点
        vis[x]=1; // 将该节点标记为已访问过
        for(reg int i=head[x];i;i=edge[i].next){ // 从该节点开始遍历其所有邻居节点,直到链表的尾部结点为止
            int y=edge[i].to,val=dis[x]+edge[i].dis; // 将邻居节点的信息存入变量y和val中
            if(dis[y]>val){ // 如果通过当前节点到达邻居节点的距离小于已知的最短距离值val.dis,则更新最短距离值和对应的节点位置信息
                dis[y]=val; // 将邻居节点的最短距离值设为val.dis
                if(!vis[y]){ // 如果邻居节点还没有被访问过,则将其加入优先队列中,按照距离从小到大排序
                    q.push((node_2){dis[y],y}); // 将邻居节点的最短距离值和位置信息存入优先队列中,按照距离从小到大排序
                }
            }
        }
    }
}

int main(){ // 主函数,程序的入口点
    n=read(),m=read(),s=read(); // 从输入中读取节点数量、边数量和起始节点编号s的值并存入相应的变量中
    edge.push_back((node_1){0,0,0}); 
    for(reg int i=1;i<=n;++i)	dis[i]=INF;
	for(reg int i=0;i<m;++i){
		int u=read(),v=read(),d=read();
		add_edge(u,v,d);
	}
	dijkstra();
	for(reg int i=1;i<=n;++i){
		write(dis[i]);
		putchar(' ');
	}
	return 0;
}
posted @ 2023-08-09 22:05  Nebulary  阅读(113)  评论(0编辑  收藏  举报