图论:SPFA算法 求最短路径 (队列优化的Ford算法)
SPFA算法 求最短路径
构建vector邻接表,和w二维数组存储边权,注意初始化为无穷大代表这两个点间没有边
vector<int>linjie[maxn];//记录邻接点
int w[maxn][maxn];//记录边权
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j)
w[i][j] = 0x7ffffff;//边权一开始都设置为无穷大
for (int i = 1; i <= m; ++i)
{
cin >> a >> b >> c;
linjie[a].push_back(b);
linjie[b].push_back(a);
w[a][b] = w[b][a] = c;
}
构建队列,和标记在不在队列里的布尔数组:
queue<int>q;
bool exist[maxn];//标记 在队列中就true 不然就false
一样的要构建d数组,记录到起点的距离,并初始化。
int d[maxn];//记录到起点的最短路径
for (int i = 0; i <= n; ++i)d[i] = 0x7ffffff;//距离一开始都设置为oo
d[s] = 0;//自己到自己的距离为0
还有路径数组pre和初始化。
int pre[maxn];//记录前驱点
pre[s] = 0;
先将起点入队,并且标记为1,表示在队列中。然后开始while()循环,while循环中,先定义一个u存储队头元素,再将队头元素出队,然后出队,就要标记为0,表示不在队列中,然后遍历u的邻接关系,定义v为u的邻接点,如果d[u]+边权<d[v],更新d[v],更新前驱点,并且如果不在队列中,就把这个点入队。注意是有更新才入队。
q.push(s);
exist[s] = true;//起点入队
while (!q.empty())
{
u = q.front();//点u出队
q.pop();
exist[u] = false;
for (int i = 0; i < linjie[u].size(); ++i)
{
v = linjie[u][i];
if (d[u] + w[u][v] < d[v])
{
d[v] = d[u] + w[u][v];//更新
pre[v] = u;
if (!exist[v])//队列中不存在v点
{
q.push(v);
exist[v] = true;
}
}
}
}
输出路径函数:
void print(int i)//递归输出路径代码
{
if (pre[i])
print(pre[i]);
cout << i << " ";
}
完整代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 105;
vector<int>linjie[maxn];//记录邻接点
int w[maxn][maxn];//记录边权
int d[maxn];//记录到起点的最短路径
int pre[maxn];//记录前驱点
queue<int>q;
bool exist[maxn];//标记 在队列中就true 不然就false
int n, m, s, u, v;
int a, b, c;
void print(int i)//递归输出路径代码
{
if (pre[i])
print(pre[i]);
cout << i << " ";
}
int main()
{
//初始化
cin >> n >> m >> s;
for (int i = 0; i <= n; ++i)d[i] = 0x7ffffff;//距离一开始都设置为oo
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j)
w[i][j] = 0x7ffffff;//边权一开始都设置为无穷大
for (int i = 1; i <= m; ++i)
{
cin >> a >> b >> c;
linjie[a].push_back(b);
linjie[b].push_back(a);
w[a][b] = w[b][a] = c;
}
d[s] = 0;//自己到自己的距离为0
pre[s] = 0;
q.push(s);
exist[s] = true;//起点入队
while (!q.empty())
{
u = q.front();//点u出队
q.pop();
exist[u] = false;
for (int i = 0; i < linjie[u].size(); ++i)
{
v = linjie[u][i];
if (d[u] + w[u][v] < d[v])
{
d[v] = d[u] + w[u][v];//更新
pre[v] = u;
if (!exist[v])//队列中不存在v点
{
q.push(v);
exist[v] = true;
}
}
}
}
for (int i = 1; i <= n; ++i)
{
cout << d[i] << endl;
print(i);
cout << endl;
}
return 0;
}