bellman_ford

bellman_ford算法:有边数限制的最短路,可以处理重边、负边和自环。

给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你求出从1号点到n号点的最多经过k条边的最短距离,如果无法从1号点走到n号点,输出impossible。

注意:图中可能 存在负权回路

输入格式

第一行包含三个整数n,m,k。

接下来m行,每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出格式

输出一个整数,表示从1号点到n号点的最多经过k条边的最短距离。

如果不存在满足条件的路径,则输出“impossible”。

数据范围

1≤n,k≤500,

1≤m≤10000,

任意边长的绝对值不超过10000。

输入样例:

3 3 1

1 2 1

2 3 1

1 3 3

输出样例:

3

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, M = 10001;
int d[N], backup[N];
int n, m, k;
struct edges{
    int a, b, w;
}Edge[M];

int bellman_ford()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    for(int i = 0;i<k;i++)
    {
        memcpy(backup, d, sizeof d);
        for(int j = 0;j < m;j++)//注意这里是要循环结束到m,因为输入的边数就是m。
        {
            int a = Edge[j].a, b = Edge[j].b, w = Edge[j].w;
            d[b] = min(d[b], backup[a] + w);
        }
    }
    if(d[n] > 0x3f3f3f3f / 2) return -1;
    return d[n];
}

int main()
{
    cin>>n>>m>>k;
    for(int i = 0;i<m;i++)
    {
        int a, b, w;
        cin>>a>>b>>w;
        Edge[i] = {a,b,w};
    }
    int t = bellman_ford();
    if(t == -1) cout<<"impossible"<<endl;
    else cout<<t<<endl;
}

限制多少边就循环多少次,放进备份数组里面是为了防止本次循环就发生串联,等到k下一次循环的时候再用重新复制过的备份数组,这样就可以在之前的基础上继续前进 而不会 超出k条边的限制了。

第一次只会更新从起点出发一条边能到达的地方,下一次就更新第二条能到达的,以此递增类推。

k = 1, d[1] = 0, d[2] = 1, d[3] = 3, 这里d[3]不会更新为d[2] + 1,因为用的是上次备份的d[2] +oo

k = 2, d[1] = 0, d[2] = 1, d[3] = min(3, 1 + 1) = 2;

for n 次

  for所有边a, b, w

    dist[b] = min(dist[b], dist[a] + w); //每次无脑的对所有的边进行松弛操作。

posted @ 2020-04-15 23:50  龙雪可可  阅读(91)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************