题目描述
定一个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
算法1
(bellman_ford) $O(n*m)$
步骤:
1.初始化时将起点s到各个顶点v的距离dist(s->v)赋值为INF,dist(s->s)赋值为0
2.后续进行最多n-1次遍历操作,对所有的边进行松弛操作,假设:
所谓的松弛,以边ab为例,若dist(a)代表起点s到达a点所需要花费的总数,dist(b)代表起点s到达b点所需要花费的总数,weight(ab)代表边ab的权重,
若存在:三角不等式:
(dist(a) +weight(ab)) < dist(b)则说明存在到b的更短的路径,s->…->a->b,更新b点的总花费为(dist(a) +weight(ab)),父节点为a
3.遍历都结束后,若再进行一次遍历,还能得到s到某些节点更短的路径的话,则说明存在负环路
详解看 这个
时间复杂度分析:两重循环时间复杂度为O(m*n)
C++ 代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,M=10010;
int dist[N],backup[N];
int n,m,k;
struct Edge{
int a,b,w;
}edges[M];
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);
}
}
if(dist[n]>0x3f3f3f3f/2)return -1;
return dist[n];
}
int main(){
cin>>n>>m>>k;
for(int i=0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
edges[i]={a,b,w};
}
int t=bellman_ford();
if(t==-1)puts("impossible");
else cout<<t<<endl;
return 0;
}
先上一组hack数据如下
2 1 1
1 2 -1
修改方案:bellman_ford()返回dist[n]然后再判断,只在输出前判断一次。
我不是很懂你说的意思
你这个代码,处理这组数据的结果是错的,后面是修补方案