给定一个 n个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible
。
注意:图中可能 存在负权回路 。
输入格式
第一行包含三个整数 n,m,k。
接下来 m 行,每行包含三个整数 x,y,,表示存在一条从点 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
思路分析:对于负权问题一般有两种解决方案一种是bellman-ford另一种是SPFA,本题存在负权但是不能使用spfa,原因如下
- 存在负环(SPFA无法解决负环)
- 规定了走k步
所以只能使用bellman-ford算法。
注意事项:
- 要有一个备份数组backdis,(保存上一轮循环更新完后1到其他点的最短路) 使用bellman-ford更新时,需要走k步,每走完一步都需要更新到其他点的最短路,更新的过程中务必保证使用backdis数组更新dis数组,只有这样才能保证一轮循环是仅仅走了一步(思考一下)。
- 因为存在负权,所以dis[n]也有可能被更新,所以判断不能到达的条件不能是dis[n]==0x3f3f3f3f。如下图所示
初始状态,假设∞=0x3f3f3f3f
走了k步(假设k=1)后
可以发现存在这样一种情况,dis[n]!=0x3f3f3f3f,所以最终不可达判断条件不能是dis[n]==0x3f3f3f3f
可以把判断条件改成dis[n]==0x3f3f3f3f/2
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 10010;
int dis[510],backdis[510];
struct node
{
int u,v,w;
}e[maxn];
void bellman_ford(int k,int n,int m)
{
memset(dis,inf,sizeof dis);
dis[1]=0;
for(int i = 0;i<k;i++)
{
memcpy(backdis,dis,sizeof dis);
for(int j = 0;j<m;j++)
{
if(dis[e[j].v]>backdis[e[j].u]+e[j].w)
{
dis[e[j].v]=backdis[e[j].u]+e[j].w;
}
}
}
if(dis[n]>inf/2) cout<<"impossible"<<endl;
else cout<<dis[n]<<endl;
}
int main()
{
int n,m,k;
cin>>n>>m>>k;
for(int i = 0;i<m;i++)
{
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
}
bellman_ford(k,n,m);
return 0;
}