Bellman-ford算法是求含负权图的单源最短路径算法,效率很低,但代码很容易写。即进行不停地松弛(原文是这么写的,为什么要叫松弛,争议很大),每次松弛把每条边都更新一下,若n-1次松弛后还能更新,则说明图中有负环,无法得出结果,否则就成功完成。
Bellman-ford算法有一个小优化:每次松弛先设一个旗帜flag,初值为FALSE,若有边更新则赋值为TRUE,最终如果还是FALSE则直接成功退出。Bellman-ford算法浪费了许多时间做无必要的松弛。
Dijkstra算法中不允许边的权是负权,如果遇到负权,则可以采用Bellman-Ford算法。
Bellman-Ford算法描述:
1,.初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
2.迭代求解:
进行循环,循环下标为从1到n-1(n等于图中点的个数)。
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
3.检验负权回路:
为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说该图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
/*
* About: Bellman-Ford算法
* Author: Tanky Woo
* Blog: www.WuTianqi.com
*/
#include < iostream >
using namespace std;
const int maxnum = 100 ;
const int maxint = 99999 ;
// 边,
typedef struct Edge{
int u, v; // 起点,重点
int weight; // 边的权值
}Edge;
Edge edge[maxnum]; // 保存边的值
int dist[maxnum]; // 结点到源点最小距离
int nodenum, edgenum, source; // 结点数,边数,源点
// 初始化图
void init()
{
// 输入结点数,边数,源点
cin >> nodenum >> edgenum >> source;
for ( int i = 1 ; i <= nodenum; ++ i)
dist[i] = maxint;
dist[source] = 0 ;
for ( int i = 1 ; i <= edgenum; ++ i)
{
cin >> edge[i].u >> edge[i].v >> edge[i].weight;
if (edge[i].u == source) // 注意这里设置初始情况
dist[edge[i].v] = edge[i].weight;
}
}
// 松弛计算
void relax( int u, int v, int weight)
{
if (dist[v] > dist[u] + weight)
dist[v] = dist[u] + weight;
}
bool Bellman_Ford()
{
for ( int i = 1 ; i <= nodenum - 1 ; ++ i)
for ( int j = 1 ; j <= edgenum; ++ j)
relax(edge[j].u, edge[j].v, edge[j].weight);
bool flag = 1 ;
// 判断是否有负环路
for ( int i = 1 ; i <= edgenum; ++ i)
if (dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)
{
flag = 0 ;
break ;
}
return flag;
}
int main()
{
// freopen("input3.txt", "r", stdin);
init();
if (Bellman_Ford())
for ( int i = 1 ;i <= nodenum; i ++ )
cout << dist[i] << endl;
return 0 ;
}
* About: Bellman-Ford算法
* Author: Tanky Woo
* Blog: www.WuTianqi.com
*/
#include < iostream >
using namespace std;
const int maxnum = 100 ;
const int maxint = 99999 ;
// 边,
typedef struct Edge{
int u, v; // 起点,重点
int weight; // 边的权值
}Edge;
Edge edge[maxnum]; // 保存边的值
int dist[maxnum]; // 结点到源点最小距离
int nodenum, edgenum, source; // 结点数,边数,源点
// 初始化图
void init()
{
// 输入结点数,边数,源点
cin >> nodenum >> edgenum >> source;
for ( int i = 1 ; i <= nodenum; ++ i)
dist[i] = maxint;
dist[source] = 0 ;
for ( int i = 1 ; i <= edgenum; ++ i)
{
cin >> edge[i].u >> edge[i].v >> edge[i].weight;
if (edge[i].u == source) // 注意这里设置初始情况
dist[edge[i].v] = edge[i].weight;
}
}
// 松弛计算
void relax( int u, int v, int weight)
{
if (dist[v] > dist[u] + weight)
dist[v] = dist[u] + weight;
}
bool Bellman_Ford()
{
for ( int i = 1 ; i <= nodenum - 1 ; ++ i)
for ( int j = 1 ; j <= edgenum; ++ j)
relax(edge[j].u, edge[j].v, edge[j].weight);
bool flag = 1 ;
// 判断是否有负环路
for ( int i = 1 ; i <= edgenum; ++ i)
if (dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)
{
flag = 0 ;
break ;
}
return flag;
}
int main()
{
// freopen("input3.txt", "r", stdin);
init();
if (Bellman_Ford())
for ( int i = 1 ;i <= nodenum; i ++ )
cout << dist[i] << endl;
return 0 ;
}