图论: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;
}

 

  

posted @ 2022-05-10 17:06  朱朱成  阅读(25)  评论(0编辑  收藏  举报