acwing ----bellman-ford与spfa算法

1.bellmax_ford算法:

其特点:能够用来求有边数限制的最短路,以及带负环的最短路,有以上这些特性都是因为:

for (int i=0;i<edgenum;i++)其最外边的for 循环,其含义是决定了从起点到终点一共用了多少条边。

 1 给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
 2 
 3 请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible。
 4 
 5 注意:图中可能 存在负权回路 。
 6 
 7 输入格式
 8 第一行包含三个整数 n,m,k。
 9 
10 接下来 m 行,每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
11 
12 输出格式
13 输出一个整数,表示从 1 号点到 n 号点的最多经过 k 条边的最短距离。
14 
15 如果不存在满足条件的路径,则输出 impossible。
16 
17 数据范围
18 1≤n,k≤500,
19 1≤m≤10000,
20 任意边长的绝对值不超过 1000021 
22 输入样例:
23 3 3 1
24 1 2 1
25 2 3 1
26 1 3 3
27 输出样例:
28 3

这个算法的核心思想是每一个点都在一次循环中更新,因为只要保证能够遍历到每一条边,所以其用的数据结构有很多,这里直接用struct 即可:

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

using namespace std;

const int N = 510, M = 10010;

struct Edge
{
    int a, b, c;
}edges[M];

int n, m, k;
int dist[N];
int last[N];//这里的last是保存上一个状态的dist,因为我们不能够用一个正在更新的dist去更新:

void bellman_ford()
{
    memset(dist, 0x3f, sizeof dist);

    dist[1] = 0;
    for (int i = 0; i < k; i ++ )
    {
        memcpy(last, dist, sizeof dist);
        for (int j = 0; j < m; j ++ )
        {
            auto e = edges[j];
            dist[e.b] = min(dist[e.b], last[e.a] + e.c);
        }
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);

    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        edges[i] = {a, b, c};
    }

    bellman_ford();

    if (dist[n] > 0x3f3f3f3f / 2) puts("impossible");
    else printf("%d\n", dist[n]);

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/48523/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/*3) ⭐️Bellman_ford算法里最后return-1的判断条件写的是dist[n]>0x3f3f3f3f/2;
而spfa算法写的是dist[n]==0x3f3f3f3f;其原因在于Bellman_ford算法会遍历所有的边,因此不管是不是和源点连通的边它都会得到更新;
但是SPFA算法不一样,它相当于采用了BFS,因此遍历到的结点都是与源点连通的,因此如果你要求的n和源点不连通,它不会得到更新,还是保持的0x3f3f3f3f。*/

对上面的last数组的解释:

如这张图:如果我们要求只用一条边从1到3,如果我们没有last数组则:

更新时:dist[2]=min(dist[2],dist[1]+1)=1;

dist[3]=min(dist[3],dist[2]+1)=2;//到这里其实已经隐含了1-》3是由:1->2->3不行,如果有last数组:这里的dist[2]=0x3f3f3f3f则dist[3]=0x3f3f3f3f不会变

dist[3]=min(dist[3],dist[1]+1)=2;

2.spfa算法:

其实其是对bellman_ford算法的优化: ⭐️ Bellman_ford算法可以存在负权回路,是因为其循环的次数是有限制的因此最终不会发生死循环;但是SPFA算法不可以,由于用了队列来存储,只要发生了更新就会不断的入队,因此假如有负权回路请你不要用SPFA否则会死循环。

/--------------------------------------------------------------------------------/

在bellman_ford 算法中for(int j=0;j<m;j++)dist[...]=......

这一步操作有很多无意义的,其实只有当dist[a]更新过,dist[b]才会变(其实就是有边相连的两个点):我们可以用bfs找一下dist会变的点,

用queue装一下,然后用这里面的点更新:

 

 1 给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
 2 
 3 请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。
 4 
 5 数据保证不存在负权回路。
 6 
 7 输入格式
 8 第一行包含整数 n 和 m。
 9 
10 接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
11 
12 输出格式
13 输出一个整数,表示 1 号点到 n 号点的最短距离。
14 
15 如果路径不存在,则输出 impossible。
16 
17 数据范围
18 1≤n,m≤105,
19 图中涉及边长绝对值均不超过 1000020 
21 输入样例:
22 3 3
23 1 2 5
24 2 3 -3
25 1 3 4
26 输出样例:
27 2

 

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

using namespace std;

const int N = 100010;

int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

int spfa()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    queue<int> q;
    q.push(1);
    st[1] = true;

    while (q.size())
    {
        int t = q.front();
        q.pop();

        st[t] = false;

        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j])
                {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }

    return dist[n];
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);

    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    int t = spfa();

    if (t == 0x3f3f3f3f) puts("impossible");
    else printf("%d\n", t);

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/48498/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 spaf算法也能判断负环:在这里:https://www.acwing.com/solution/content/42308/

posted @ 2022-05-01 16:58  次林梦叶  阅读(69)  评论(0)    收藏  举报