Bellman-Ford + Floyd

126 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

Bellman-Ford

算法思想

image.png 这个算法存边直接开一个结构体即可,不用什么邻接表之类的

  1. for循环n次
  2. for循环所有边 a, b, w:表示存在一条从a走到b的边,权重是w
  3. 更新一下最短距离:dist[b] = min(dist[b], dist[a] + w)

注意:

  1. 求最短路的时候,如果有负权回路的话,最短路不一定存在

时间复杂度:

O(m * n)

题目

www.acwing.com/problem/con… image.png 有负权边:不能用Dijkstra算法 有边数限制:存在负权回路也无所谓的

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510, M = 10010;

int n, m, k;
int dist[N], backup[N]; // dist:存的距离 backup:	

struct Edge // 存所有边,a:起点; b:终点; c = 权重
{
    int a, b, w;
}edges[M];

int bellman_ford()
{
    // 初始化
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    
    for (int i = 0; i < k; i++)
    {
        // 每次进行一次新的迭代之前,给dist数组备份一下
        memcpy(backup, dist, sizeof dist);
        // 遍历所有边
        for (int j = 0; j < m; j++)
        {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            dist[b] = min(dist[b], backup[a] + w); // 只用上一次更新迭代结果来更新这次的距离
        }
    }
    
    return dist[n];	
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    // 读入m条边
    for (int i = 0; i < m; i++)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }
    
    int t = bellman_ford();
    
    if (t > 0x3f3f3f3f / 2) puts("impossible"); // 最短路不存在
    else  printf("%d\n", t);
    
    return 0;
}

Floyd

算法思想

image.png 这个算法存边直接开一个结构体即可,不用什么邻接表之类的

  1. for循环n次
  2. for循环所有边 a, b, w:表示存在一条从a走到b的边,权重是w
  3. 更新一下最短距离:dist[b] = min(dist[b], dist[a] + w)

注意:

  1. 求最短路的时候,如果有负权回路的话,最短路不一定存在

时间复杂度:

O(m * n)

题目

www.acwing.com/problem/con… image.png 有负权边:不能用Dijkstra算法 有边数限制:存在负权回路也无所谓的

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510, M = 10010;

int n, m, k;
int dist[N], backup[N]; // dist:存的距离 backup:	

struct Edge // 存所有边,a:起点; b:终点; c = 权重
{
    int a, b, w;
}edges[M];

int bellman_ford()
{
    // 初始化
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    
    for (int i = 0; i < k; i++)
    {
        // 每次进行一次新的迭代之前,给dist数组备份一下
        memcpy(backup, dist, sizeof dist);
        // 遍历所有边
        for (int j = 0; j < m; j++)
        {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            dist[b] = min(dist[b], backup[a] + w); // 只用上一次更新迭代结果来更新这次的距离
        }
    }
    
    return dist[n];	
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    // 读入m条边
    for (int i = 0; i < m; i++)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }
    
    int t = bellman_ford();
    
    if (t > 0x3f3f3f3f / 2) puts("impossible"); // 最短路不存在
    else  printf("%d\n", t);
    
    return 0;
}