“ Ctrl AC!一起 AC!”
回顾之前的Dijkstra算法,会发现,算法中的数组pre总是保持着最优路径,当出现多种边权时需要严谨的判断才能对pre进行正确的更新。这里我们可以用更简单的方法:先在Dijkstra算法中记录下所有最短的路径,然后从中选出一条第二尺标最优的路径。
第一步:使用Dijkstra算法记录所有最短路径
因为要记录所有最短路径,那么每个点的前驱节点可能有多个,我们可以定义一个容器数组:
vector<int> pre[MAXV],这样就能记录每个点的所有前驱结点了,初始化为空,不需赋值。
当d[u]+G[u][v]<d[v]时 更新d[v],清空pre[v],往pre[v]中添加点u
当d[u]+G[u][v]==d[v]时 直接往pre[v]中添加点u
vector<int> pre[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]==false&&d[j]<MIN){
u=j;
MIN=d[j];
}
}
if(u==-1) return;
vis[u]=true;
for(int v=0;v<n;v++){
if(vis[v]==false&&G[u][v]!=INF){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u]+G[u][v]==d[v]){
pre[v].push_back(u);
}
}
}
}
}
第二步:遍历所有最短路径,找到第二尺标最优的路径
每个点的前驱结点都遍历一遍就会形成多条最短路路径。
我们遍历每条路径,不断更新第二尺标最优的路径。
我们再用DFS写递归函数,进行递归遍历,并寻找最优解,需要有的变量有:
·第二指标最优值optValue
·记录最优路径path(vector储存)
·记录临时路径tempPath (vector储存)
伪码描述:
int optvalue;
vector<int> pre[MAXV];
vector<int> path,tempPath;
void DFS(int v){ //v为当前访问的点
if(v==st){ //等于起点表示逆序遍历结束了
tempPath.push_back(v);
int value;
计算路径tempPath上的value值;
if(value优于optvalue){
optvalue=value;
path=tempPath;
}
tempPath.pop_back();
return;
}
tempPath.push_back(v);
for(int i=0;i<pre[v].size();i++){
DFS(pre[v][i]);
}
tempPath.pop_back();
}
其中计算tempPath路径上的value值需要注意:由于递归,这条路径是逆序的,需要逆序处理,但如果是求和,可以直接算。下面举两个例子:
//求边权之和
int value=0;
for(int i=tempPath.size()-1;i>0;i--){
int id=tempPath[i],idNext=tempPath[i-1];
value+=V[id][idNext] //点id到点idNext的边权
}
//求点权之和
int value=0;
for(int i=tempPath.size()-1;i>=0;i--){
int id=tempPath[i];
value+=W[id];
}
感谢阅读!!!
“ Ctrl AC!一起 AC!”