算法特点(权值可正可负,判断负环)
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]);
}
}
}
}