Bellman-ford算法应对有向图中有权值为负的情况下求最短路径

#include<iostream>
#include<vector>
#include<set>
#include<stack>
#include<stdlib.h>

using namespace std;

const int MaxNumber=1e10;
struct EdgeType //边的类型
{
 int fromvertex; //边的起点
 int tovertex;  //边的终点
 double weight; //边上的权值
};

template<class vertexType>
class DirectedGraphofMatrix //邻接矩阵存储的有向图
{
 private:
  vector<vertexType>vertex; //顶点向量
  int vertexnum; //顶点数目
  vector<EdgeType>edge; //边向量
  int edgenum; //边的数目
  double *Distance; //Distance表示从起始顶点到各个目标顶点的权值
  int *path; //path[i]表示第i个顶点在最短路径中的父顶点
  int *indegree; //顶点的入度
        int sourcevertex; //源点
        bool *Changed; //Changed[i]==false表示Distance[i]没有被更新,否则,表示Distance[i]被更新
       
  int getposofvertex(vertexType& v); //求出顶点v在图中的位置
  vertexType getvertex(int i); //求出顶点i代表的元素
  double getWeight(int fromvertex,int tovertex); //获取顶点fromvertex到tovertex之间的权值
  void SetChanged(); //将Changed都设置为false
  bool CheckChanged(); //检查Changed是不是都是false
  void UpdateEdge(EdgeType& e); //更新边,更新Distance,path,Changed
  void printeachpath(int i); //打印从起始顶点到顶点i的一条最短路径
 public:
  DirectedGraphofMatrix(int n,int m);
  void TopSort(); //拓扑排序
  void Initializationwork(vertexType& startvertex); //在求最短路径前的初始化工作
  void LoopAdjustEdge(); //循环调整边
  void showGraph() const;
  void printshortestpath(); //打印从起始顶点到其余顶点的最短路径
};

bool checkInputFormat(istream& is) //检查输入格式是否正确
{
 if(!is.good())
 {
  cerr<<" 输入格式错误!"<<endl;
  return false;
 }
 else return true;
}

template<class vertexType>
DirectedGraphofMatrix<vertexType>::DirectedGraphofMatrix(int n=0,int m=0):vertexnum(n),edgenum(m)
{
 int i;
 vertexType v;
 EdgeType e;
 for(i=0;i<n;i++)
 {
  cout<<"请输入第"<<i<<"个顶点:";
  cin>>v;
  if(!checkInputFormat(cin)) return;
  else this->vertex.push_back(v);
 }
 for(i=0;i<m;i++)
 {
  cout<<" 请输入第"<<i<<"条边的起点:";
  cin>>e.fromvertex;
  cout<<" 请输入第"<<i<<"条边的终点:";
  cin>>e.tovertex;
  cout<<" 请输入第"<<i<<"条边的权值:";
  cin>>e.weight;
  this->edge.push_back(e);
 }
 Distance=new double[vertexnum];
 path=new int[vertexnum];
 this->indegree=new int[vertexnum];
 this->Changed=new bool[vertexnum];
 if(!Distance || !path || !indegree || !Changed) exit(0);
}


template<class vertexType>
void DirectedGraphofMatrix<vertexType>::TopSort()
{
 stack<int>vertex_stack; //保存入度为0的顶点序号
 int n=0; //拓扑排序中得顶点数目
 int i,j,k;
 for(i=0;i<this->vertexnum;i++)
 {
  if(this->indegree[i]==0)
  {
   vertex_stack.push(i); //将第i个顶点入栈
   n++;
  }
 }
 while(vertex_stack.empty()==false)
 {
  i=vertex_stack.top();
  vertex_stack.pop();
  for(k=0;k<this->edgenum;k++)
  {
   if(this->edge[k].fromvertex==i)
   {
    j=this->edge[k].tovertex;
    this->indegree[j]--;
    if(this->indegree[j]==0) //第j个顶点入度为0
    {
     vertex_stack.push(j);
     n++;
    }
   }
  }
 }
 if(n!=vertexnum)
 {
  cerr<<" 有向图中存在环路!"<<endl;
  exit(0);
 }
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::UpdateEdge(EdgeType& e)
{
 int i,j;
 i=e.fromvertex;
 j=e.tovertex;
 if(this->Distance[i]+this->getWeight(i,j)<this->Distance[j])
 {
  this->Distance[j]=this->Distance[i]+this->getWeight(i,j); //更新Distance[j]
  this->path[j]=i; //更新path[j],i是j的最短路径上的父节点
  this->Changed[j]=true; //表明第j个顶点的Distance已经改变
 }
}


template<class vertexType>
void DirectedGraphofMatrix<vertexType>::LoopAdjustEdge()
{
 int i;
 do
 {
  for(i=0;i<edgenum;i++) //对所有边进行调整
  {
   this->UpdateEdge(this->edge[i]);
  }
  if(this->CheckChanged()==true) return; //一轮调整后Changed未发生改变,边更新完毕
  this->SetChanged(); //否则将Changed都置为false,进行下一轮调整
 }while(true);
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::showGraph() const
{
 int i;
 for(i=0;i<this->vertexnum;i++)
 {
  cout<<" 第"<<i<<"个顶点是:"<<this->vertex[i]<<endl;
 }
 for(i=0;i<this->edgenum;i++)
 {
  cout<<" 第"<<i<<"条边的起点是:"<<this->edge[i].fromvertex<<endl;
  cout<<" 第"<<i<<"条边的终点是:"<<this->edge[i].tovertex<<endl;
  cout<<" 第"<<i<<"条边的权值是:"<<this->edge[i].weight<<endl;
 }
}

template<class vertexType>
int DirectedGraphofMatrix<vertexType>::getposofvertex(vertexType& v)
{
 int i;
 for(i=0;i<this->vertexnum;i++)
 {
  if(v==this->vertex[i]) return i;
 }
 return -1;
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::SetChanged()
{
 int i;
 for(i=0;i<vertexnum;i++) this->Changed[i]=false;
}

template<class vertexType>
bool DirectedGraphofMatrix<vertexType>::CheckChanged() //Changed元素都是false,函数返回true
{
 int i;
 for(i=0;i<vertexnum;i++)
 {
  if(this->Changed[i]==true) return false;
 }
 return true;
}
 
template<class vertexType>
vertexType DirectedGraphofMatrix<vertexType>::getvertex(int i)
{
 int j;
 for(j=0;j<vertexnum;j++)
 {
  if(i==j) return this->vertex[i];
 }
}

template<class vertexType>
double DirectedGraphofMatrix<vertexType>::getWeight(int fromvertex,int tovertex)
{
 int i;
 for(i=0;i<edgenum;i++)
 {
  if(this->edge[i].fromvertex==fromvertex && this->edge[i].tovertex==tovertex)
  {
   return this->edge[i].weight;
  }
 }
 return MaxNumber;
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::Initializationwork(vertexType& startvertex) //在求最短路径前的初始化工作
{
 int i;
 sourcevertex=this->getposofvertex(startvertex); //获取源点序号
 if(sourcevertex==-1)
 {
  cerr<<"输入的源点不存在,程序终止!"<<endl;
  exit(0);
 }
 for(i=0;i<this->vertexnum;i++)
 {
  this->indegree[i]=0; //将所有顶点入度清零
  this->Changed[i]=false; //初始时所有Changed[i]都为false;
 }
 for(i=0;i<this->edgenum;i++)
 {
  this->indegree[this->edge[i].tovertex]++; //统计所有顶点入度
 }
 this->Distance[sourcevertex]=0;
 for(i=0;i<vertexnum;i++)
 {
  if(i!=sourcevertex) this->Distance[i]=MaxNumber;
  this->path[i]=-1;
 }
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::printeachpath(int i)
{
 int parent; //parent是当前顶点的父顶点
 double d=this->Distance[i]; //d是起始顶点到顶点i的最短路径长度
 stack<int>s; //栈s用于保存最短路径上的顶点
 cout<<" 起始顶点到顶点"<<this->getvertex(i)<<"的最短路径是:";
 while((parent=this->path[i])!=-1) //顶点i有父顶点
 {
  s.push(parent);
  i=parent;
 }
 while(!s.empty())
 {
  cout<<this->getvertex(s.top())<<" ";
  s.pop();
 }
 cout<<d<<endl;
}

template<class vertexType>
void DirectedGraphofMatrix<vertexType>::printshortestpath()
{
 int i;
 for(i=0;i<vertexnum;i++)
 {
  this->printeachpath(i);
 }
}

void main()
{
 int n,m;
 cout<<"请输入顶点个数:";
 cin>>n;
 cout<<" 请输入边的个数:";
 cin>>m;
 DirectedGraphofMatrix<char>g(n,m);
 char sourcevertex;
 cout<<"请输入源点:";
 cin>>sourcevertex;
 g.Initializationwork(sourcevertex);
 g.showGraph();
 g.TopSort();
 g.LoopAdjustEdge();
 g.printshortestpath();
}
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/wangzhicheng1983/article/details/7650703
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞