您的位置:首页 > 其它

SPFA算法

2018-03-12 22:18 141 查看

SPFA算法

用途

用于解决单源最短路径问题,可以处理含有负边权边的图(若存在源点可达负环则无解)。

算法描述

SPFA算法是在Bellman-Ford算法基础上改进得来的 (关于BF算法可参考 《Bellman-Ford算法》)。BF算法时间复杂度较高,原因在于每一次循环都需要遍历图中所有边,其中包含了大量的重复遍历,这就会使算法效率大大降低。SPFA算法依据的原理是:只有当某个结点到源点的最短距离d[i]改变后,由结点i出发可达的结点j与源点的最短距离d[j]才可能会被改变。由此可以对BF算法进行优化得到期望时间复杂度为O(kE)O(kE) (k为常数,E为边数)的SPFA算法,其主要步骤如下:

建立队列q,将源点入队;

队首结点u出队,遍历u的所有出边 u->v 进行松弛操作,如果 d[u] + length[u->v] < d[v], 则用较小值更新d[v],若此时v不在队列中,则将其入队;

当队列非空时,重复步骤2,同时每次操作要判断是否有某个结点的入队次数大于 n - 1,若有则说明图中存在从源点可达的负环,结束算法并返回false;

所有最短距离优化完毕,结束算法并返回true。

代码实现

const int maxn = 1000;
const int INF = 1000000000;

struct node
{
int v, l;
};

vector<node> adjL[maxn];        // 邻接表
int n;                          // 结点个数
int d[maxn];                    // 结点i到源点的最短距离
int num[maxn];                  // 结点i的入队次数
bool inq[maxn];                 // 结点i是否已入队

bool SPFA(int s)
{
for (int i = 0; i < n; i++)         // 初始化
{
num[i] = 0;
d[i] = INF;
inq[i] = false;
}
d[s] = 0;               // 源点到自身距离为0

queue<int> q;
q.push(s);              // 源点入队
num[s]++;
inq[s] = true;

while (!q.empty())      // 队非空一直循环
{
int u = q.front();          // 队首结点出队
q.pop();
inq[u] = false;

for (int i = 0; i < adjL[u].size(); i++)        // 遍历所有出边
{
int v = adjL[u][i].v;
int l = adjL[u][i].l;
if (d[u] + l < d[v])        // 松弛
{
d[v] = d[u] + l;
if (!inq[v])
{
q.push(v);
inq[v] = true;
num[v]++;
if (num[v] > n - 1)         // 入队次数超过 n - 1,说明存在源点可达负环,返回false
return false;
}
}
}
}
return true;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 SPFA 最短路径