介绍
全称Bellman-Ford算法,目的是求解有负权边的最短路径问题。
考虑环,根据环中边的边权之和的正负,将环分为零环、正环、负环。其中零环、正环不会影响最短路径的求解,而负环会影响最短路径的求解。
可用BF算法返回一个bool值来判断是否有负环,如果有返回false,否则返回true.
bool BF(int b){fill(path,path+maxn,INF);path[b]=0;//求最短距离for(int i=0;i<n-1;i++){//比较趟数for(int j=0;j<n;j++){//遍历每一个顶点相关的邻接边for(int k=0;k<table[j].size();k++){int v=table[j][k].v;int value=table[j][k].value;if(path[j]+value<path[v]){//此时path[v]应该是最小距离path[v]=path[j]+value;}}}//判断是否有负环:有返回false,无返回truefor(int m=0;m<n;m++){//再次遍历边时for(int k=0;k<table[m].size();k++){int v=table[m][k].v;int value=table[m][k].value;if(path[m]+value<path[v])//还能找到有比path[v]更小的距离return false;//说明有负环存在}}return true;//否则无负环}
}
设计思想
将求最短路径看作是求以源点为根结点的一棵最短路径树,此时图与起点均确定,因此最短路径树也就确定了,且最短路径树的层数一定不超过顶点个数V,即树中两顶点的比较更新次数不超过V-1轮。
实现
由于用邻接矩阵遍历边时,复杂度会达到O(V的3次方),因此我们使用邻接表去实现
应用
由于求最短路径条数时,BF算法会重复遍历相同的顶点,因此在有多条最短路径数时,最短路径条数的累加会出错。于是我们想到用set容器记录前驱结点,通过遍历去重后的前驱结点进行累加。
set容器的介绍
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
const int maxn=100;
const int INF=1000000000;
struct node{int v;//邻接顶点int value;//对应边权//通过构造函数实现定义同时初始化node(int a,int b):v(a),value(b){}
};
vector<node> table[maxn];
int n,edge,st,ed,weight[maxn];int path[maxn],num[maxn],w[maxn];
set<int> pre[maxn];//记录前驱,以便去重void BF(int b){fill(path,path+maxn,INF);memset(num,0,sizeof(num));memset(w,0,sizeof(w));path[b]=0;w[b]=weight[b];num[b]=1;for(int i=0;i<n-1;i++){for(int j=0;j<n;j++){for(int k=0;k<table[j].size();k++){//记录int v=table[j][k].v;int value=table[j][k].value;if(path[j]+value<path[v]){path[v]=path[j]+value;w[v]=w[j]+weight[v];num[v]=num[j];//小于覆盖pre[v].clear();//清空pre[v].insert(j);//记录最短路径前驱}else if(path[j]+value==path[v]){if(w[v]<w[j]+weight[v])w[v]=w[j]+weight[v];pre[v].insert(j);//继续记录num[v]=0;//防止重复计数,清空//重新累加计数:通过遍历前驱结点实现for( set<int>::iterator it=pre[v].begin();it!=pre[v].end();it++)num[v]+=num[*it];//*it=pre[j][k],即k的前驱}}}}}int main(){int v1,v2,weigh;cin>>n>>edge>>st>>ed;for(int i=0;i<n;i++)cin>>weight[i];for(int j=0;j<edge;j++){//构建邻接表cin>>v1>>v2>>weigh;table[v2].push_back(node(v1,weigh));table[v1].push_back(node(v2,weigh));}BF(st);cout<<num[ed]<<" "<<w[ed]<<endl;return 0;
}