bellman_ford

bellman_ford(贝尔曼-福特)算法:因为dijkstra算法不能处理带负权边的图,这时候就可以利用bellman_ford算法。( 设想从我们可以从图中找到一个环路(即从v出发,经过若干个点之后又回到v)且这个环路中所有路径的权值之和为负。那么通过这个环路,环路中任意两点的最 短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。 而Bellman-Ford算法具有分辨这种负环路的能力)

时间复杂度:O(ne)——n是点数,e是边数。如果是邻接阵的话应该就是O(n^3).


联系:可以优化成SPFA。可以用来写差分约束

实现过程:设G为加权有向图 V是所有结点的集合 E是所有路径的集合 S表示源点 n表示V中所有结点的数目 weight(u,v)表示从结点u  到结点v的路径的权值。 Distanz(v)表示从源点s出发到结点v的最短路径的距离,(或者说是从s到v所有的路径中权值的最小值)。Predecessor(v)表示节点 v的父结点

在Bellman-Ford算法结束之后,可以输出,G是不是包含一个负环路。如果G不包含负环路,那么Distanz就存储了从s出发到所有结点的距离。

Bellman-Ford算法的伪代码如下:
========================================
01 for 每一个结点v 属于 V
02 Distanz(v) := 无穷大, Predecessor(v) := null
03 Distanz(s) := 0,Predecessor(s):= null;

04 循环 n-1 次
05     for 每一条路径 (u,v)属于 E
06         if Distanz(u) + weight(u,v) < Distanz(v)
07         then
08            Distanz(v) := Distanz(u) + weight(u,v)
09            Predecessor(v) := u;

10 for 每一条路径 (u,v)属于 E
11     if Distanz(u) + weight(u,v) < Distanz(v)
12     then
13       中止程序并且返回 “找到负循环”
14 返回
==============================================

下面是我用bellman_ford 和静态邻接表写的hdu2544

代码
   
     
#include < iostream >
using namespace std;
const long point_maxn = 105 ;
const long edge_maxn = 10005 ;
const long lmaxn = 1000000000 ;
int n;
int m;
struct node
{
int v;
int w;
int next;
}edge[edge_maxn];
int pre[point_maxn];
int dirs[point_maxn];
void Init()
{
int i,j;
int a,b,c;
int Index = 1 ;
memset(pre,
- 1 , sizeof (pre));
for (i = 0 ;i < m;i ++ )
{
int flag;
scanf(
" %d%d%d " , & a, & b, & c);
for (flag = 0 ,j = pre[a];j !=- 1 ;j = edge[j].next)
{
if (edge[j].v == b)
{
if (edge[j].w > c)
{
edge[j].w
= c;
}
flag
= 1 ;
break ;
}
}
if (flag == 1 )
continue ;
edge[Index].v
= b;
edge[Index].w
= c;
edge[Index].next
= pre[a];
pre[a]
= Index ++ ;
swap(a,b);
for (flag = 0 ,j = pre[a];j !=- 1 ;j = edge[j].next)
{
if (edge[j].v == b)
{
if (edge[j].w > c)
{
edge[j].w
= c;
}
break ;
}
}
edge[Index].v
= b;
edge[Index].w
= c;
edge[Index].next
= pre[a];
pre[a]
= Index ++ ;
}
}
int bellman_ford()
{
int i,j,k;
fill(dirs,dirs
+ point_maxn,lmaxn);
int start = 1 ;
int end = n;
dirs[start]
= 0 ;
for (i = 0 ;i < n - 1 ;i ++ )
{
for (j = 1 ;j <= n;j ++ )
{
for (k = pre[j];k !=- 1 ;k = edge[k].next)
{
int s = j;
int e = edge[k].v;
if (dirs[e] > dirs[s] + edge[k].w)
{
dirs[e]
= dirs[s] + edge[k].w;
}
}
}
}
for (j = 1 ;j <= n;j ++ )
{
for (k = pre[j];k !=- 1 ;k = edge[k].next)
{
int s = j;
int e = edge[k].v;
if (dirs[e] > dirs[s] + edge[k].w)
{
return 0 ;
}
}
}
return 1 ;
}
void print()
{
if ( ! bellman_ford())
{
printf(
" -1\n " );
}
else
{
printf(
" %d\n " ,dirs[n]);
}
}
int main()
{
while (scanf( " %d%d " , & n, & m) != EOF && (n != 0 || m != 0 ))
{
Init();
print();
}
return 0 ;
}

 

你可能感兴趣的:(for)