最短路(基础篇)

全源最短路模板

Floyd

我们设 \(f_{i,j}\) 表示 \(i\)\(j\) 的最短路,于是我们枚举中转点 \(k\),就有 \(f_{i,j}\leftarrow\min(f_{i,j},f_{i,k}+f_{k,j})\)

于是简单枚举一下进行转移即可,时间复杂度 \(O(n^3)\)

代码:

for(k=1;k<=n;k++){
	for(x=1;x<=n;x++){
		for(y=1;y<=n;y++){
			f[x][y]=min(f[x][y],f[x][k]+f[k][y]);
		}
	}
}

单源最短路模板

单源最短路径

我们考虑一条边 \(u\rightarrow v\),我们尝试进行松弛:\(dis_v\leftarrow\min(dis_v,dis_u+w(u,v))\)

于是 \(Bellman-Ford(SPFA)\) 算法所做的,就是尝试不断对每条边进行松弛。每进行一轮循环,就将图上所有的边松弛一次,于是复杂度为 \(O(nm)\)

注意:如果一条边被松弛了 \(n\) 次及以上,说明图中存在负环

因为 \(Bellman-Ford\) 严格不优于,所以我们给出 \(SPFA\) 的实现(只是多了一个队列优化):

int spfa(int S,int T){
	int hh=0,tt=1;
	memset(d,0x3f,sizeof d);
	q[0]=S;st[S]=1;d[S]=0;
	while(hh!=tt){
		int t=q[hh++];
		if(hh==N)hh=0;
		st[t]=0;
		for(int i=h[t];~i;i=ne[i]){
			int j=e[i];
			if(d[j]>d[t]+w[i]){
				d[j]=d[t]+w[i];
				if(!st[j]){
					q[tt++]=j;
					if(tt==N)tt=0;
					st[j]=1;
				}
			}
		}
	}
	return d[T]>=d[0]/2?d[0]:d[T];
}

单源最短路径(强化版)

上述算法会被卡掉,所以我们考虑一种新的最短路算法 \(dijkstra\)

我们考虑现在有两个集合,一个是已经确定最短路的 \(S\),剩下的则是 \(T\).

初始化 \(dis_s=0\),然后从 \(T\) 中选取一个最短路长度最小的点,把他移动到 \(S\) 中,然后对所有新移动到 \(S\) 中的点的出边执行松弛操作。

堆优化代码:

void dijkstra(int s){
  	memset(dis,0x3f,sizeof(dis));
  	dis[s]=0;
  	q.push({0,s});
  	while(!q.empty()){
    	int u=q.top().u;
    	q.pop();
    	if(vis[u])continue;
    	vis[u]=1;
    	for(auto ed:e[u]){
      		int v=ed.v,w=ed.w;
      		if(dis[v]>dis[u]+w){
        		dis[v]=dis[u]+w;
        		q.push({dis[v],v});
      		}
    	}
  	}
}
posted @ 2024-09-12 11:49  zxh923  阅读(3)  评论(0编辑  收藏  举报