迪杰斯特拉求最短路的步骤是每次找最距离源点最近的点进行更新。
SPFA求最短路的步骤是用被更新过的点来做下一次更新。当一个点被松弛之后,判断该点是不是已经在队列中,不在的话压入队列。
需要注意的是,虽然说SPFA是Bellman-Ford算法的优化,但是准确的说是假优化,事实上,所有Bellman-Ford算法的优化都会被精心构造的图卡回Bellman-Ford的复杂度。然而,Bellman-Ford及其优化的算法(包括SPFA)可以用来判断负环。(感觉这是唯一的剩余价值了)
SPFA代码:
ll dis[1010];
ll vis[1010];
ll head[1010];
struct node
{
ll v, w, next;
} e[10010];
ll ct = 1;
queue<ll> q;
void SPFA(ll s)
{
q.push(s);
fill(dis, dis + 1010, INF);
dis[s] = 0;
while (q.size())
{
ll u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].next)
{
ll v = e[i].v;
ll w = e[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
void add(ll u, ll v, ll w)
{
e[ct].v = v;
e[ct].w = w;
e[ct].next = head[u];
head[u] = ct++;
}
int main()
{
int t, n;
cin >> t >> n;
while (t--)
{
ll u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
SPFA(1);
cout << dis[n] << endl;
return 0;
}
SPFA更应该掌握的是用来判断图中是否存在负环,其实很简单,我们只需要在在松弛操作的时候记录层数,SPFA本身是BFS的层级拓展,无负环的图经过n-1次可以到达所有点。存在负环的话,自然就会超过n-1次松弛了。
AC代码:
ll vis[1010];
ll head[1010];
ll cot[1010];
struct node
{
ll v, w, next;
} e[10010];
ll ct = 1, flag = 0;
ll n, m, w;
queue<ll> q;
void SPFA(ll s)
{
q.push(s);
fill(dis, dis + 1010, INF);
dis[s] = 0;
while (q.size() && !flag)
{
ll u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].next)
{
ll v = e[i].v;
ll w = e[i].w;
if (dis[v] > dis[u] + w)
{
cot[v] = cot[u] + 1; //记录层数
if (cot[v] >= n)
{
flag = 1;
break;
}
dis[v] = dis[u] + w;
if (!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
void add(ll u, ll v, ll w)
{
e[ct].v = v;
e[ct].w = w;
e[ct].next = head[u];
head[u] = ct++;
}
int main()
{
ll t;
cin >> t;
while (t--)
{
ct = 1, flag = 0;
fill(head, head + 1010, 0);
fill(cot, cot + 1010, 0);
fill(vis, vis + 1010, 0);
cin >> n >> m >> w;
for (int i = 1; i <= m; i++)
{
ll u, v, ww;
cin >> u >> v >> ww;
add(u, v, ww);
add(v, u, ww);
}
for (int i = 1; i <= w; i++)
{
ll u, v, ww;
cin >> u >> v >> ww;
add(u, v, -ww);
}
SPFA(1);
if (flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}