Dijkstra算法
Dijkstra算法解决的是单源最短路径问题,即给定图
G
(
V
,
E
)
G(V,E)
G(V,E)和起点
s
s
s,求从给定起点
s
s
s到其他顶点的最短距离。
算法思想
设置集合
V
V
V为未访问的顶点集,
S
S
S为已被访问的顶点的集合,然后执行n次(顶点个数)下面两步:
①每次从集合
V
V
V中选择与起点
s
s
s的最短距离最小的一个顶点,记为
u
u
u,设置为已访问并加入
S
S
S。
②令顶点
u
u
u为中介点,遍历
s
s
s通过
u
u
u能够到达的顶点,如果通过
u
u
u能够缩短
s
s
s到其他顶点的距离,则优化最短距离。
程序模板
邻接矩阵版
const int MAXV=1000;
const int INF=0x3f3f3f3f;
bool vis[MAXV]= {false};
int n,G[MAXV][MAXV];
//记录最短路径中每个点的前一个顶点
vector<int> pre[MAXV];
//起点到达各点的距离
int d[MAXV];
void dijkstra(int s) {
fill(d,d+MAXV,INF);
//起点到自身的距离为0
d[s]=0;
for(int i=0; i<n; i++) {
int u=-1,MIN=INF;
for(int j=0; j<n; j++) {
if(!vis[j] && d[j]<MIN) {
u=j;
MIN=d[j];
}
}
//找不到小于INF的d[u],说明剩下的点不连通或者全部访问过了
if(u==-1) return;
vis[u]=true;
for(int v=0; v<n; v++) {
if(!vis[v] && G[u][v]!=INF){
if(d[u]+G[u][v]<d[v]) {
d[v]=d[u]+G[u][v];
//由于最短路径更新,所以v的前一顶点也要更新
pre[v].clear();
pre[v].push_back(u);
}else if(d[u]+G[u][v]==d[v]){
pre[v].push_back(u);
}
}
}
}
}
邻接表版
const int MAXV=1000;
const int INF=0x3f3f3f3f;
bool vis[MAXV]= {false};
vector<int> pre[MAXV];
int n,d[MAXV];
struct Node {
//v为下一顶点,dis为距离
int v,dis;
};
vector<Node> adj[MAXV];
void dijkstra(int s) {
fill(d,d+MAXV,INF);
d[s]=0;
for(int i=0; i<n; i++) {
int u=-1,MIN=INF;
for(int j=0; j<n; j++) {
if(!vis[j] && d[j]<MIN) {
u=j;
MIN=d[j];
}
}
if(u==-1) return;
vis[u]=true;
//只有下面不同
for(int j=0; j<adj[u].size(); j++) {
int v=adj[u][j].v;
if(!vis[v]){
if(d[u]+adj[u][j].dis<d[v]) {
d[v]=d[u]+adj[u][j].dis;
pre[v].clear();
pre[v].push_back(u);
}else if(d[u]+adj[u][j].dis==d[v]){
pre[v].push_back(u);
}
}
}
}
}
第二标尺
有些题目需要结合一些别的条件,称为第二标尺,比如点权、边权(花费)、路径数量等,可以使用上述的模板得出pre之后,结合DFS来求出考虑第二标尺的结果:
我们需要新增加三个变量
①全局变量的第二标志最优值optValue
②记录最优路径的path(vector)
③记录DFS遍历时的临时路径tmpPath(vector)
int optValue;
vector<int> path,tmpPath;
void DFS(int v,int s){
// 递归边界
if(v==s){
tmpPath.push_back(v);
int value;
// **************
// 根据题意,计算此路径的 value(第二标尺)
// **************
if(value>optValue){
optValue=value;
path=tmpPath;
}
tmpPath.pop_back();
return;
}
// 递归式
tmpPath.push_back();
for(int i=0;i<pre[v].size();i++){
DFS(pre[v][i]);
}
tmpPath.pop_back();
}