从城市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;
}
持续更新中。。。。。。