Bellman-ford算法应对有向图中有权值为负的情况下求最短路径
来源:互联网 发布:理智与情感赏析知乎 编辑:程序博客网 时间:2024/05/16 23:57
#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();}