最短路

\(dijkstra\)

朴素的\(dijkstra\)

时间复杂度\(O(n^2)\),每次枚举取出到已有状态最短的一个点加入进行更新。

堆优化的\(dijikstra\)

每次取出堆顶的元素进行更新,然后把被更新的元素加入堆中,堆按从小到大排序,可以保证时间复杂度在\(O(n\log n)\)

然而,无论哪种\(dijkstra\)都是无法处理负权边的,其无法保证正确性,因为更长的路加上负权边以后可能会小于原来的最短路。

void dijkstra(){
	memset(dist, 0x3f3f3f3f, sizeof(dist));
	priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
	q.push(make_pair(0, s));
	dist[s] = 0;
	while(!q.empty()){
		pair<int, int> u = q.top();
		q.pop();
		if(vis[u.second])	continue;
		vis[u.second] = 1;
		for(register int i = head[u.second]; i; i = ne[i]){
			if(dist[e[i]] > v[i]+u.first){
				dist[e[i]] = v[i]+u.first;
				q.push(make_pair(dist[e[i]], e[i]));
			}
		}
	}
}

\(Bellman-Ford\)

朴素的\(Bellman-Ford\)

时间复杂度\(O(nv)\),基于对\(v-1\)条边的枚举操作。

堆优化的\(Bellman-Ford——SPFA\)

\(SPFA\)并不能保证时间复杂度,在最坏的情况下可以被卡成和不带优化的\(Bellman-Ford\)一样。因此在仅存在正边的情况下使用堆优化的\(dijkstra\)是最优的。而\(Bellman-Ford\)的堆优化大多用于存在判负环的情况。

void SPFA(){
	memset(dist, 0x3f3f3f3f, sizeof(dist));
	dist[s] = 0;
	queue<int> q;
	q.push(s);
	vis[s] = 1;
	while(!q.empty()){
		int t = q.front();
		q.pop();
		vis[t] = 0;
		for(int i = head[t]; i != -1; i = ne[i]){
			int w = e[i];
			if(dist[w] > dist[t] + v[i]){
				dist[w] = dist[t] + v[i];
				if(!vis[w]){
					q.push(w);
					vis[w] = 1;
				}
			}
		}
	}
}

\(Floyd\)

可以在\(n^3\)的时间内求出任意两点之间的最短路,且常数小除了负权回路都可以跑,其在稠密图上的时间复杂度远优于进行\(n\)次的堆优化\(dijkstra\)

void floyd(){
	for(register int i = 1; i <= n; ++i)
		for(register int j = 1; j <= n; ++j)
			for(register int k = 1; k <= n; ++k)
				if(dist[i][j]+dist[k][i] < dist[k][j])
					dist[k][j] = dist[i][j]+dist[k][i];
}
posted @ 2024-10-09 18:31  Zzzzzzzm  阅读(7)  评论(0)    收藏  举报