最短路 Bellman-ford算法
- 可以用来解决带负值的最短路,并且可以用来判断负环
- 时间复杂度o(m*n) (m是边数,n是点数)
- 具体步骤:
用 u[] v[] w[]来存一条边 松弛的时候每次用 u[i]-v[i]这条边来松弛 初始点到 v[i]这条边。核心代码如下:
for(int i=1;i<=n-1;i++)///松弛次数
{
for(int j=1;j<=m;j++)///每条边松弛
{
if(dis[v[j]]>dis[u[j]]+w[j])
dis[v[j]]=dis[u[j]]+w[j];
}
}
至于为什么要松弛 n-1次呢 ?松弛k 次就是 a-b之间最多通过k个点来相连,然而一个n个顶点的最短路径最多就n-1 条边,所以n-1次以后一定能够找到最短路。完整代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define inf 0x3f3f3f3f
using namespace std;
int u[1010];
int v[1010];
int w[1010];
int n,m;
int dis[1010];
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
dis[i]=inf;
for(int i=1;i<=m;i++)
cin>>u[i]>>v[i]>>w[i];
dis[1]=0;
for(int i=1;i<=n-1;i++)///松弛次数
{
for(int j=1;j<=m;j++)///每条边松弛
{
if(dis[v[j]]>dis[u[j]]+w[j])
dis[v[j]]=dis[u[j]]+w[j];
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<endl;
}
/*5 5 2 3 2 1 2 -3 1 5 5 4 5 2 3 4 3*/
0
-3
-1
2
4
- 检测负环(负权回路)只要再加几行语句就行,就是让他在松弛一次,看看dis[]数组是还能改变,能改变就说明有负权回路,反之则没有
int flag=0;
for(int i=1;i<=m;i++)
if(dis[v[j]]>dis[u[j]]+w[j])
flag=1;
if(flag==1)
cout<<"有负权回路"<<endl;