1. 程式人生 > >最短路演算法Floyed, Dijkstra, Bellman-Ford, SPFA

最短路演算法Floyed, Dijkstra, Bellman-Ford, SPFA

Floyed演算法,複雜度o(n^3);

更新i->j的距離,通過中介點k,如果能夠通過k使得i->j的距離更短,那麼更新。

程式碼

void Folyed() {
    for (int k = 0; k < n; k++) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (i != j && i != k && j != k && d[i][j] > d[i][k] + d[k][j]) {
					d[i][j] = d[i][k] + d[k][j];
				}
			}
		}
	}
}

Dijkstra演算法,普通複雜度O(n^2),堆優化O(nlgn)

有個集合s,和原始圖G,一個最短距離陣列d。從起點開始,每次新增一個u,如果能夠從中介點u更新到u所有的鄰接點v的最短距離,那麼當前可以更新的是起點到v的最短距離d[v]。直到s中包括所有點,演算法結束,最後d陣列就是起點到其他所有點的最短距離。

堆優化的話,就避免很多重複邊的判斷。

void Dijkstra(int st, int ed) {
	memset(d, INF, sizeof(d));
	memset(vis, false, sizeof(vis));
	d[st] = 0;
	for (int i = 0; i < n; i++) {
		int u = -1, MIN = INF;
		for (int j = 0; j < n; j++) {
			if (vis[j] == false && d[j] < MIN) {
				MIN = d[j];
				u = j;
			}
		}
		if (u == -1) return;
		vis[u] = true;
		for (int v = 0; v < n; v++) {
			if (vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) {
				d[v] = d[u] + G[u][v];
			}
		}
	}
}

堆優化。 

struct edge {
	int v;
	int d;//距離
	edge(){}
	edge(int _v, int _d) {
		v = _v;
		d = _d;
	}
};
vector<edge> E[maxn];
void Clear() {
	for (int i = 0; i < maxn; i++) {
		E[i].clear();
	}
	memset(pre, 0, sizeof(pre));
}
struct node {
	int v;
	int d;
	bool operator<(const node &a)const{
		return d > a.d;
	}
};
void Dijkstra(int st, int ed) {
	memset(d, INF, sizeof(d));
	memset(minCost, INF, sizeof(minCost));
	memset(vis, false, sizeof(vis));
	d[st] = 0;
	minCost[st] = 0;
	priority_queue<node> q;
	q.push(node{st, 0});
	while (!q.empty()) {
		node f = q.top(); q.pop();
		int u = f.v;
		if (vis[u] == true) continue;
		vis[u] = true;
		for (int i = 0; i < E[u].size(); i++) {
			int v = E[u][i].v;
			if (vis[v] == true) continue;
			if (d[v] > d[u] + E[u][i].d) {
				d[v] = d[u] + E[u][i].d;
				pre[v] = u;
				q.push(node{v, d[v]});
			}
		}
	}
}

Bellman-Ford,複雜度O(n*E),頂點數n,邊數E

void bellman-ford() {
	for (int i = 0; i < n - 1; i++) {//最多n-1次
		for (int u = 0; u < n; u++) {
			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;
				}
			}
		}
	}
}

SPFA,複雜度O(k*E),k平均值一般等於2

spfa演算法就是對bellman-ford的一種佇列優化,避免了很多無意義的判斷和操作。

bool SPFA(int s) {
	memset(inq, false, sizeof(inq));
	memset(num, 0, sizeof(num));
	memset(d, INF, sizeof(d));
	prority_queue<int> q;
	q.push(s);
	inq[s] = true;
	num[s]++;
	d[s] = 0;
	while (!q.empty()) {
		int u = q.top(); 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]) {
					inq[v] = true;
					q.push(v);
					num[v]++;
					if (num[v] > n-1) return false;
				}
			}
		}
	}
	return true;
}