SPAF

虽然Bellman-Ford 算法的思路很简洁,但是O(VE)的复杂度很高,然后怎么办呢?优化嘛,Bellman-Ford 算法的每轮操作都需要操作所有边,显然这个其中会有大量无意义的操作,严重影响算法性能,

只有当某个顶点u的 d[u]改变时,从它出发的边的邻接点v 的d[v]才有可能改变

是不是想到了什么???对了就是队列。

我们建立一个队列,每次将队首的顶点元素u取出,然后对u出发的所有边都松弛一遍,就是判断 d[u]  + length[ u->v ] < d[v] 是否成立,如果成立就用 d[u]  + length[ u->v ] 覆盖 d[v] 于是d[v]获得更优值。如果v不在队列中就加入队列,这样操作指导队列为空(说明图中没有从源点可达的负环),或是某个顶点的入队次数超过V - 1(说明图中存在从源点可达的负环)

伪代码

queue Q;
源点入队 
while(队列非空){
	取出队首元素u;
	for(u的所有邻接边u->v){
		if(d[u] + dis < d[v]){
			d[v] = dis + d[u];
			if(v 当前不在队列里){
				v入队;
				if(v入队次数大于n-1){
					说明有可达的负环, return ; 
				} 
			} 
		}
	} 
}

优化后的算法叫SPFA,期望时间复杂度为O(kE)E为边数,k是常数,如果有负环,退化为O(VE).

vector Adj[MAXV];
int n, d[MAXV], num[MAXV];
bool inq[MAXV];

bool SPFA(int s) {
	memset(inq, false, sizeof(inq));
	memset(num, 0, sizeof(num));
	fill (d, d + MAXV, INF);
	queue Q;
	Q.push(s);
	inq[s] = true;
	num[s] ++;
	d[s] = 0;
	while(!Q.empty()){
		int u = Q.front();
		Q.pop();
		inq[u] = false;
		for(int j = 0; j < Adj[u].size(); j++){
			int v = Adj[u][j].v;
			int dis = Adj[u][j].dis;
			if(d[u] + dis < d[v]){
				d[v] = d[u] + dis;
				if(!inq[v]){
					Q.push(v);
					inq[v] = true;
					num[v] ++;
					if(num[v]  >= n) return false;
				}
			} 
		} 
	}
	return true;
}

 

你可能感兴趣的:(SPFA)