bellmen-ford算法,与dijkstra不同,bellman-ford可以运用于有负权值的图,不过复杂度很高,O(N*M )… 慎用~(可以用SPFA,它bwllman-ford的扩展)
Bellman-ford算法同样是对每条边进行N-1次松弛,当有权值为负时,对所有边进行N-1次松弛,如果dis还能更新,说明有负环。
ps:名词解释【负环】 在一个图里每条边都有一个权值(有正有负)
如果存在一个环(从某个点出发又回到自己的路径),而且这个环上所有权值之和是负数,那这就是一个负权环,也叫负权回路
存在负权回路的图是不能求两点间最短路的,因为只要在负权回路上不断兜圈子,所得的最短路长度可以任意小。
Bellman-ford原理:
1.如果最短路存在,则每个顶点最多经过一次,因此不超过n-1条边;
2.长度为k的路由长度为k-1的路加一条边得到;
3.由最优性原理,只需依次考虑长度为1,2,…,k-1的最短路。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int inf=0x3f3f3f3f;
int main()
{
int i,k,n,m;
int u[10],v[10],w[10],dis[10];
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++)
scanf("%d%d%d",&u[i],&v[i],&w[i]);
for(i=0; i<=n; i++)
dis[i]=inf;
dis[1]=0;
int flag;
for(k=1; k<n; k++)
{
flag=0; //标记dis数组会不会变化
//进行一轮松弛
for(i=1; i<=m; i++)
{
if(dis[v[i]]>dis[u[i]]+w[i]) //表示u[i]->v[i]这条边的值+1号顶点到u[i]点的值是否小于原来1号顶点到u[i]点的值
{
dis[v[i]]=dis[u[i]]+w[i];
flag=1;//dis数组更新
}
}
if(flag==0) break; //表示数组松弛完毕
}
flag=0; //检验是否会出现负环
for(i=1; i<=m; i++)
if(dis[v[i]]>dis[u[i]]+w[i]) flag=1; //若还能松弛则存在负环
if(flag==0)
{
for(i=1; i<=n; i++)
printf("%d ",dis[i]);
printf("\n");
}
else
printf("此图存在负环回路\n");
return 0;
}
Bellman-Ford 算法往往不到n-1轮就已经松弛完毕,用标记变量可以减少循环次数。
在这个算法中加入队列进行优化就是SPFA算法,等看懂了在写一下。