介绍
Dijkstra算法是用来解决最短路径问题的一个常用算法;常用于解决单源最短路径问题,即给定一个起点S,求出其到图各个顶点的最小距离。其本质思想是贪心思想。
解释
图文解释
https://blog.youkuaiyun.com/lbperfect123/article/details/84281300
文字解释
先建立数组:
vector<node>G[100005];//实现图(邻接表实现)
int dis[100005];//记录起点s到j的最短距离
bool visted[100005];//判断顶点j是否访问过
【注意】要初始化d[],G[][];
1.每次从未攻占的城市中选择据s最近的城市【u】,进行攻占;
2.以u为中介,优化所有能从u到达的&未访问的节点
3.执行n次上面两步操作;
代码实现
下面是一个模板。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
/*
思路:
*/
struct node{
int to;//顶点
int val;//边的长度
node(int a,int b){
to=a;
val=b;
}
};
vector<node>G[100005];
int dis[100005];
bool visted[100005];
int n;
void Dijkstra(int s){
fill(dis,dis+100005,inf);//初始化
dis[s]=0;//s到s最近~
for(int i=1;i<=n;i++){//找出未访问的定点中据起点最近的点
int u=-1,Min=INT_MAX;
for(int j=1;j<=n;j++){
if(!visted[j]&&Min>dis[j]){
u=j;
Min=dis[j];
}
}//找出距离s的最近的 & 未访问的 点u
if(u==-1)return;
visted[u]=1;//标记为已经访问
for(int j=0;j<G[u].size();j++){
int f=G[u][j].to;
int val=G[u][j].val;
if(!visted[f]&&dis[f]>dis[u]+val)
dis[f]=dis[u]+val;
//更新dis[]
}
}
}
int main(){
int m,s;
cin>>n>>m>>s;
while(m--){
int u,v,w;
cin>>u>>v>>w;
G[u].push_back(node(v,w));
G[v].push_back(node(u,w));
}
Dijkstra(s);
cout<<dis[1];
for(int i=2;i<=n;i++)
cout<<" "<<dis[i];
return 0;
}
拓展
只会模板是不能够应对复杂(gou)多变的题目的;下面就来讨论一些最短路径之外的附加条件(即第二标尺)如何实现;
1.再增加一个边权
如果要考虑经过一条边时有花费,求在保证路径最短的情况下,花费最少。
思路
再加一个量
struct node{
int to;//顶点
int val;//边的长度
int cost;//过边的花费
node(int a,int b){
to=a;
val=b;
}
};
代码实现
for(int j=0;j<G[u].size();j++){
int f=G[u][j].to;
int val=G[u][j].val;
if(!visted[f]){
if(dis[f]>dis[u]+val)//dis[]能更新
dis[f]=dis[u]+val;
else if(dis[f]==dis[u]+val&&cost[f]>cost[u]+G[u][j].cost)
cost[f]>cost[u]+G[u][j].cost;
//当路径最优时,保证花费最少
}
}
2.再增加一个点权
情况与增加边权类似,不再赘述。
3.求最短路径条数
int num[100005];//记录起点s到j的最短路径条数。
for(int j=0;j<G[u].size();j++){
int f=G[u][j].to;
int val=G[u][j].val;
if(!visted[f]){
if(dis[f]>dis[u]+val){
dis[f]=dis[u]+val;
num[f]=num[u];//最短路径更新时,num[u]覆盖num[f]
}
else if(dis[f]==dis[u]+val){
num[f]+=num[u];
//最短距离相同时累加
}
}
}