图论--第K短路(A*思想)
k短路求解:
k短路 = 单源点最短路跑反向边 + 高级搜索A*
A*算法 结合了启发式方法和形式化方法;
启发式方法通过充分利用图给出的信息来动态地做出决定而使搜索次数大大降低;
形式化方法不利用图给出的信息,而仅通过数学的形式分析;
算法思路:
算法通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向;
当这条路径失败时,它会尝试其他路径;
对于A*,估价函数=当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数值最小的一个;
对于K短路算法来说,g(p)为当前从s到p所走的路径的长度;h(p)为点p到t的最短路的长度;
f(p)的意义为从s按照当前路径走到p后再走到终点t一共至少要走多远;
为了加速计算,h(p)需要在A*搜索之前进行预处理,从终点t做一次单源点最短路径就能得到每个点的h(p)了;
算法步骤:
(1),以原终点t为源点,求解t到所有点的最短距离(即:跑一遍最短路);
(2),新建一个优先队列,将源点s加入到队列中;
(3),从优先级队列中弹出f(p)距离最小的点p,如果点p就是t,则计算t出队的次数;
如果当前为t的第k次出队,则当前路径的长度就是s到t的第k短路的长度,算法结束;
否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先级队列;
代码:
struct B{ ll x,t; B(ll x,ll t):x(x),t(t){} friend bool operator < (B aa,B bb){ return aa.t+dis[aa.x]>bb.t+dis[bb.x]; //优先队列,dis为预处理以终点为起点最短路 } }; ll ASTAR()//A*求第k条边 { if(dis[s]>=inf) return -1; priority_queue <B> q; B re(s,0); int num=0; q.push(re); while(!q.empty()) { re=q.top(); q.pop(); if(re.x==e) { num++; if(num==k)//找到第k条路 return re.t; } for(int i=pre2[re.x];~i;i=a2[i].next)//进队 { q.push(B(a2[i].y,a2[i].len+re.t)); } } return -1; }