853. 有边数限制的最短路

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

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

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

输入格式

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

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

输出格式

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

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

数据范围

1n,k5001≤n,k≤500,
1m100001≤m≤10000,
任意边长的绝对值不超过10000。

输入样例:

3 3 1
1 2 1
2 3 1
1 3 3

输出样例:

3


//贝尔曼算法处理有负权边的图
//整体思路:两重循环,第一重循环循环n次(n表示所有的点数),第二重循环,循环所有的边a,b,w
//每重循环更新所有的边dist[b] = min(dist[b],dist[a] + w); ---> 这个更新的操作又叫做松弛操作
//贝尔曼算法证明了---->所有的边一定满数dist[b] <= dist[a] + w(这玩意又叫三角不等式)
//如果有负权回路,那么最短路不一定存在,负权回路为负无穷
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

//N表示点数,M表示边数
const int N = 510,M = 1e4+10;
//n表示n个点,m表示m条边,k表示边数限制
int n,m,k;

//距离
int dist[N];
//备份防止串联,避免一个点更新其他点,限制这个点只能用上一个结点迭代的结果
int backup[N];

//定义一个结构体存所有的边
struct{
    //a,b表示起点和终点,w表示所有的权重
    int a,b,w;
}edges[M];//edges表示存所有的边的


int bellman_ford(){
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;
    
    for(int i = 0;i < k;i++){//先从直达开始找最短距离

        //对上一个结果进行备份,防止串联使用当前结果
        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);//用上一次迭代的结果更新我们当前的距离
        }
    }
    
    //考虑到负权边,所以如果两个正无穷边为负权,有一方较小的情况也会进行更新
    //题目给定不超过10000
    if(dist[n] > 0x3f3f3f3f / 2){
        return -1;
    }else{
        return dist[n];
    }
    
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    
    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 == -1) puts("impossible");
    else printf("%d\n",t);
    return 0; 
}

  

猜你喜欢

转载自www.cnblogs.com/luyuan-chen/p/11774895.html