最短路(Dijkstra Floyd Bellman-Ford SPFA模板及例题 一次性搞定最短路问题)

从城市A到城市B,有时候可以直达也可以途径其他城市到达,怎样选择最短的路径到达就是最短路问题。

分为单源最短路(所有点到某一特定点的最短路径)和多源最短路(任意两点间的最短路径)。根据边的正负也可以分为带负权边和不带负权边的最短路。

Dijkstra用于解决不含负权边的单源最短路。基本思想:记S为已经找到到源点的最短路的点的集合,dis【i】表示顶点i到源点的最短距离。每次取不在S中的dis值最小的点u,将点u加入S并优化u周围点的dis值,重复直至所有点都在S中。

Dijkstra伪代码:

(1)初始化S,将源点加入S。

(2)初始化dis数组:for(T中每个与源点S有边相连的点u)dis【u】=min(dis【u】,w(u,s));

(2)while(S不包含所有的顶点)do{

                   u=min(dis【u】&& u不在S中);

                   u加入S;

                   for(每个不在S中的顶点v && dis【v】>dis【u】+w(u,v))dis【v】=dis【u】+w(u,v);

          }

因为while循环和每次都要找dis最小的点,算法的时间复杂度为o(n^2),所以通常采用Dijkstra的队列优化版来解题(采用优先队列保存S中的点,这样就不用每次都去找dis最小的点)

队列优化模板:

/*zhizhaozhuo
Dijkstra优先队列模板 AND HUD-2544*/
#include<cstdio> 
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=110,INF=1e9;
int vis[maxn],dis[maxn];
struct node{
	int to,len;
	node(int to,int len):to(to),len(len){} //方便插入vector
	bool operator<(const node& a)const{return len>a.len;}//用于优先队列排序,从小到大排
};
vector<node>Map[maxn];
void Dijkstra(int s,int n){
	for(int i=1;i<=n;i++)dis[i]=INF;
	memset(vis,0,sizeof(vis));
	dis[1]=0;
	priority_queue<node>Q;
	Q.push(node(1,dis[1]));
	while(!Q.empty()){
		node u=Q.top();Q.pop();
		if(vis[u.to])continue;
		vis[u.to]=1;
		for(int i=0;i<Map[u.to].size();i++){
			node v=Map[u.to][i];
			if(dis[v.to]>dis[u.to]+v.len){
				dis[v.to]=dis[u.to]+v.len;
				Q.push(node(v.to,dis[v.to]));
			}
		}
	}
}
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)&&n){
		for(int i=0;i<=n;i++)Map[i].clear();
		for(int i=0;i<m;i++){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			Map[a].push_back(node(b,c));
			Map[b].push_back(node(a,c));
		}
		Dijkstra(1,n);
		printf("%d\n",dis[n]);
	}
	return 0;
}

持续更新中。。。。。。

猜你喜欢

转载自blog.csdn.net/love_phoebe/article/details/81483429