算法导论 24.1 Bellman-Ford算法

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-22 18:13   26   0

一,Bellman-Ford算法的思想

Bellman-Ford算法(以下简称BF算法),用于解决边的权重可以为负值的单源最短路径,它通过对边进行松弛操作逐渐降低从源结点s到各结点v的最短路径估计值v.d,直到该估计值与实际的最短路径权重δ(s,v)相同。

二,Bellman-Ford算法介绍

准备阶段:一副赋值有向图,每个结点有两个属性:d和π,分别表示从源结点到该结点的最短路径和前驱结点

算法过程:初始化各结点,对每条边进行|V|-1次松弛处理,处理完后检查是否存在环路,返回t/f,算法中有两个重要的证明,一个是为何对每条边进行|V|-1次松弛后能够确保v.d=δ(s,v),另一个是为何v.d>u.d+w(u.v)时存在环路

(1)为何对每条边进行|V|-1次松弛后能够确保v.d=δ(s,v)?

最坏的情况下,从源结点到一个结点的最短路径需要经过所有结点、所有边,即每条边的最坏情况是需要|V|-1次松弛。

(2)为何v.d>u.d+w(u.v)时存在环路?

因为通过(1)我们知道在经过|V|-1次松弛之后能确保v.d=δ(s,v),那么v.d应该<=u.d+w(u,v),不可能出现v.d>u.d+w(u.v)的情况,如果出现只有可能存在环路,每次relax都会使v.d无限缩小。

三,Bellman-Ford算法伪代码

在给出BF算法伪代码之前,我们先给出BF算法需要用到的两个方法的伪代码

INITIALIZE_SINGLE_SOURCE(G,s)

1. for each vertex v∈G.V

2. v.d=∞

3. v.π=NULL

4. s.d=0

RELAX(u,v,w)

1. if v.d>u.d+w(u,v)

2. v.d=u.d+w(u,v)

3. v.π=u

BELLMAN_FORD(G,w,s)

1. INITIALIZE_SINGLE_SOURCE(G,s)

2. for i=1 to |G.V|-1

3. for each edge(u,v)∈G.E

4. RELAX(u,v,w)

5. for each edge(u,v)∈G.E

6. if v.d>u.d+w(u.v)

7. return FALSE

8. return TRUE

第1行,对结点的d和π值进行初始化;第2-4行,我们对每条边进行|V|-1次松弛操作;第5-7行,对每条边进行检查,检查是否存在权值为赋值的环路,如果存在环路,返回false;第8行,返回true,说明存在最短路。


四,Bellman-Ford算法的复杂度

时间复杂度:初始化的时间为O(V),双重循环的时间为O((V-1)*E),检查的时间为O(E),因此总时间为O(V+V*E-E+E)=O((V+1)*E)=O(V*E)

五,Bellman-Ford算法的代码

//解决单源最短路径,权重可为负,返回布尔值表示是否存在一个从源节点可以到达的权重为负的环路,若存在环路,则不能解决,否则给出最短路径和权重
bool Bellman_Ford_Algo(Graph * graph, Node * startNode)
{
 Initialize_Single_Source(graph, startNode);//初始化结点的d和π
 for (int i = 1; i < graph->getNodeList().size(); i++) {//对图的每条边进行relax,需要进行节点数-1轮
  for (int j = 0; j < graph->getEdgeList().size(); j++) {
   RELAX(graph->getEdgeList()[j]->getStartNode(), graph->getEdgeList()[j]->getEndNode(), graph->getEdgeList());
  }
 }
 for (int k = 0; k < graph->getEdgeList().size(); k++) {//对每条边检查是否存在权重为负值的环路,若不存在环就应该满足v.distance<=u.distance+u到v的距离
  if (graph->getEdgeList()[k]->getEndNode()->getDistance() > graph->getEdgeList()[k]->getStartNode()->getDistance() + graph->getEdgeList()[k]->getDistance())
   return false;
 }
 return true;
}
void Initialize_Single_Source(Graph * graph, Node * startNode)
{
 for (int i = 0; i < graph->getNodeList().size(); i++)
 {
  graph->getNodeList()[i]->setDistance(10000000);
  graph->getNodeList()[i]->setPrevNode(NULL);
 }
 startNode->setDistance(0);
}
void RELAX(Node * u, Node * v, vector<Edge *> edges)
{
 Edge *uvedge = NULL;
 for (int i = 0; i < edges.size(); i++)
 {
  if (edges[i]->getStartNode() == u && edges[i]->getEndNode() == v)
  {
   uvedge = edges[i];
  }
 }

 if (v->getDistance() > u->getDistance() + uvedge->getDistance())
 {
  v->setDistance(u->getDistance() + uvedge->getDistance());
  v->setPrevNode(u);
 }
}



分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP