Dijkstra(迪杰斯特拉)算法是一种经典的求单源最短路的算法,大体上就是利用已经找到的点的最短路去推其他点的最短路。
我们先将图中的点分为两部分:
S:已经找到最短路的点
T:图G - S,剩下的点
具体过程如下:
- 将dis数组初始化为INF,源点s,dis[s] = 0,s点加入S集,s点为当前点
- 重复以下步骤:
- 遍历当前点的子点,如果当前点的子点dis值 > dis[当前点]+其之间边的边权,将子点dis值更新为dis[当前点]+其之间边的边权
- 在T集中找出一个dis值最小的点移入S集,并将其作为当前点
- 直到T集为空时,结束
经过上述步骤之后,dis数组内的值便是每一点到源点的最短路值。
示例代码(kuangbin模板):
const int MAXN=1010;
#define typec int
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大
bool vis[MAXN];
int pre[MAXN];
void Dijkstra(typec cost[][MAXN], typec lowcost[], int n,int beg){
for(int i=0;i<n;i++){
lowcost[i]=INF; vis[i]=false; pre[i]=−1;
}
lowcost[beg]=0;
for(int j=0;j<n;j++){
int k=−1;
int Min=INF;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[i]<Min){
Min=lowcost[i];
k=i;
}
if(k==−1)break;
vis[k]=true;
for(int i=0;i<n;i++)
if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i]){
lowcost[i]=lowcost[k]+cost[k][i];
pre[i]=k;
}
}
}
算法中每次寻找T集中dis值最小的点的复杂度为O(n),我们可以用堆(heap)来优化这一过程,使其复杂度降到O(logn),这样总体复杂度降到O(nlogn)。
示例代码(kuangbin模板):
const int INF=0x3f3f3f3f;
const int MAXN=1000010;
struct qnode{
int v;
int c;
qnode(int _v=0,int _c=0):v(_v),c(_c){}
bool operator <(const qnode &r)const{
return c>r.c;
}
};
struct Edge{
int v,cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[MAXN];
bool vis[MAXN];
int dist[MAXN];
//点的编号从 1 开始
void Dijkstra(int n,int start){
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++) dist[i]=INF;
priority_queue<qnode>que;
while(!que.empty())que.pop();
dist[start]=0;
que.push(qnode(start,0));
qnode tmp;
while(!que.empty()){
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])continue;
vis[u]=true;
for(int i=0;i<E[u].size();i++){
int v=E[tmp.v][i].v;
int cost=E[u][i].cost;
if(!vis[v]&&dist[v]>dist[u]+cost){
dist[v]=dist[u]+cost;
que.push(qnode(v,dist[v]));
}
}
}
}
void addedge(int u,int v,int w){
E[u].push_back(Edge(v,w));
}