图论: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 @   朱朱成  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示