SPFA 算法

//SPFA 算法 今天再偶然的情况下发现了另一种最小路径的方法 正常来说 求最小路径只有两种方法
//gijkstra方法挺好的就是不能处理权值为负的情况 而Ford算法又比较难实现 复杂度高
//首先谈谈我对这个算法的理解吧。这个算法可以处理权值为负数的情况
//但是却没有办法有权值为负的环 这个可以在后面解释 这个和他本身算法有关 
//首先用3个一维数组  一个一维数组是用来记录该节点进入队列的次数 如果超过n的话就
//可以证明这个为负权值的环  它就是有点类似BFS 处理与自己相关的节点 如果可以进行松弛
//并且该节点并不在队列里面就放入队列 直到队列为空就结束
//BFS中每一个节点最多就是走一次 但是这里只要你的节点不在队列里面 并且可以松弛的话就可以进入多次
//意味自己如果自身改变的话 就要通过自身改变相关的值


//好了说到现在 其实SPFA的复杂度理论上比FORD要小 KE吧 K就是每个节点进入队列的次数 但是这里说
//每一个节点进入的次数不超过两次就是2K  这个没有证明也就是倍受争议
//所以一般比赛就用dijkstra  FORD  SPFA一般会被卡死(数据很容易被卡死 但是容易事想)
#include <stdio.h>  
#include <cstring>  
#include <iostream>  
#include <algorithm>  
#include <queue>  
using namespace std;  
const int maxn=300001;  
const int inf =0x7ffffff;  
struct edge  
{  
    int from,to,w,next;  
}e[1000001];  
int head[maxn];  
int vis[maxn];  
int dist[maxn];  
int n,m,t;  
void add(int i,int j,int w)  
{  
    e[t].from=i;  
    e[t].to=j;  
    e[t].w=w;  
    e[t].next=head[i];  
    head[i]=t++;  
}  
void spfa(int s)  
{  
    queue <int> q;  
    for(int i=1;i<=n;i++)  
    dist[i]=inf;  
    memset(vis,false,sizeof(vis));  
    q.push(s);  
    dist[s]=0;  
    while(!q.empty())  
    {  
        int u=q.front();  
        q.pop();  
        vis[u]=false;  
        for(int i=head[u];i!=-1;i=e[i].next)  
        {  
            int v=e[i].to;  
            if(dist[v]>dist[u]+e[i].w)  
            {  
                dist[v]=dist[u]+e[i].w;  
                if(!vis[v])  
                {  
                    vis[v]=true;  
                    q.push(v);  
                }  
            }  
        }  
    }  
}  
memset(head,-1,sizeof(head)); 
t=0; 
//这里比较难理解的应该是把边加入相关数据之中 这个需要一个数组来帮助 这个数组就是说明下一个节点

//是再原来节点的第几个

如果这个节点本来就在对列里面就不需要再次进入栈

猜你喜欢

转载自blog.csdn.net/hnust_lizeming/article/details/76206356