最短路(SPFA)

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

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的最短路 
queueq;  
  
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]);  
                }  
            }  
        }  
     }  


你可能感兴趣的:(ACM)