spfa求最短路径,其思想就是遍历每一个点,将没有入队的点入队,从这个点开始不断修改能够修改的最小路径,直到队空。不过这里一个点可以重复入队。
这个需要有存图的基础--------->前向星存图
举个栗子
这里有一张图,边旁边的数字为这条边的权值。旁边的图为边的编号
用dis[i]来记录起点到i的最小路径长度(一开始都是inf)
求最小路径,首先从起点开始,遍历起点的每一条出边,并将要修改dis[i]的出边终点(没有入队的点)入队,再不断出队,对每个队中的点进行相同的操作。
模拟一下。
首先将①入队。dis[1]=0。①的第一条出边的终点是②,将②入队,同时修改dis[2]=3.
下一条出边是第四条边,终点为③,将③入队,修改dis[3]=4.
将④入队,dis[4]=6。
进行完这一步,①出队,同时将①标记为未入队,对②进行操作。
②的第一条出边的终点为①,不修改,不入队。
next:终点为③,9+3>4,不修改 ,不入队。
next:将⑥入队,dis[6]=10+3=13
如此不断更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
来我们看一下代码
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #define spfa zhx_akioi using namespace std; long long n,m,s,head[10001],num; long long dis[50008],vis[50008]; queue <long long> q; const int inf=2147483647; struct Edge{ int next,to,dis; }edge[500008]; void add(int f,int t,int d) { num++; edge[num].next=head[f]; edge[num].to=t; edge[num].dis=d; head[f]=num; } void spfa() { for(int i=1;i<=n;i++) dis[i]=inf;//最开始先把每个点到起点的距离设为无限大 dis[s]=0;//起点到起点的距离是0 vis[s]=1;//将起点入队,用vis标记是否在队里 q.push(s); while(!q.empty()) {int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].next)//从出队的点开始,遍历这个点的每条出边 { int v=edge[i].to; if(dis[v]>dis[u]+edge[i].dis)//如果这个点当前到起点的距离大于出队的点到起点的距离加上当前边的距离,即可以更新,就更新,并将更新的点入队 { dis[v]=dis[u]+edge[i].dis; if(vis[v]==0) {q.push(v); vis[v]=1;//标记 } } } } } int main() { scanf("%lld%lld%lld",&n,&m,&s); for(int i=1;i<=m;i++) {int f,t,d; scanf("%lld%lld%lld",&f,&t,&d); add(f,t,d);//存图 } spfa(); for(long long i=1;i<=n;i++) printf("%lld ",dis[i]); }