最短路(SPFA)

SPFA算法是一种用于解决单源最短路径问题的算法,尤其适用于处理可能存在负权边的情况。它通过队列进行松弛操作更新源点到所有点的最短路径,并能检测负环。算法的时间复杂度为O(ke),其中k通常小于等于2,e为边的数量。若某边的松弛操作超过n次,则表明存在负环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法特点(权值可正可负,判断负环)

1.用来求解单源最短路径,源点到任意点的最短路。
2.算法介绍:建立一个队列q,初始时队列里只有一个起始点,在建立一个数组dis记录起始点到所有点的最短路径,并且初始化这个数组。然后进行松弛操作,用 队列里面的点去刷新起始点到所有点的最短路,如果刷新成功且刷新点不再队列中则把该点加入到队列最后,重复执行直到队列为空。
3.时间复杂度:O(ke),k指的是所有顶点的进队的平均次数,可以证明k<=2,e为边数
4.可以用SPFA来存在是否存在环,如果是的话就是存在一条边的松弛操作大于等于n。

int n,m;//n个点 m条边 
int first[maxn],next[maxn];//first[i]存储的是节点i的第一条边的编号,nest[i]存储的是编号为i的边的下一条边的编号。 
int star[maxn],even[maxn],value[maxn];//star[i]表示编号为i的边的起点,even[i]表示编号为i的边的终点,value[i]表示编号为i的边的权值。
int dis[maxn];//dis[i] 表示的源点到i的最短路 
queue<int>q;  
  
void input()
{  
    scanf("%d%d" , &n , &m);  
    for(int i = 1 ; i <= n ; i++) /*初始化表头*/
    {
        first[i] = -1;  
        next[i] = -1;  
    }  
     /*读入m条边*/  
    for(int i = 0 ; i < m ; i++)
    {
        scanf("%d%d%d",&star[i],&even[i],&value[i]);  
        star[i+m] = even[i];  
        even[i+m] = star[i];  
        value[i+m] = value[i];  
        next[i] = first[star[i]];/*由于要插入表头,所以将原先表头后移*/  
        first[star[i]] = i;/*插入表头*/  
        next[i+m] = first[star[i+m]];  
        first[star[i+m]] = i+m;  
     }  
}  
  
void SPFA(int s)
{ 
    while(!q.empty())  
        q.pop();  
    int vis[maxn];  
    memset(vis , 0 , sizeof(vis));  
    for(int i = 1; i <= n; i++) /*初始化dis*/ 
        dis[i] = INF;  
    dis[s] = 0;  
    q.push(s);/*将源点加入队列*/  
    vis[s] = 1;/*源点标记为1*/  
    while(!q.empty())
    {  
        int x = q.front();  
        q.pop();  
        vis[x] = 0;/*注意这里要重新标记为0,说明已经出队*/  
        for(int i = first[x]; i != -1; i = next[i]) /*枚举和点x有关的所有边*/ 
        { 
            if(dis[even[i]] > dis[x] + value[i])/*松弛操作,利用三角不等式*/  
            {
                dis[even[i]] = dis[x] + value[i];  
                if(!vis[even[i]])/*如果该点不再队列里面*/
                {  
                    vis[even[i]] = 1;                  
                    q.push(even[i]);  
                }  
            }  
        }  
     }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值