給定一張n個點(編號1,2…n),m條邊的有向圖,求從起點s到終點t的第k短路的長度,路徑允許重複經過點或邊。
注意:每條最短路中至少要包含一條邊。
輸入格式
第一行包含兩個整數n和m。
接下來m行,每行包含三個整數a,b和l,表示點a與點b之間存在有向邊,且邊長為l。
最後一行包含三個整數s,t和k,分別表示起點s,終點t和第k短路。
輸出格式
輸出佔一行,包含乙個整數,表示第k短路的長度,如果第k短路不存在,則輸出「-1」。
資料範圍
1≤s,t≤n≤1000
0≤m≤105
1≤k≤1000
1≤l≤100
輸入樣例:
2 2
1 2 5
2 1 4
1 2 2
輸出樣例:
14
思路:a*演算法就是在bfs上加了乙個啟發函式,也就是乙個距離的估值,從而使搜尋更直接,更準確,避免了許多不必要的搜尋,a*演算法的一條定理,只要估計值f(s)<= 實際距離d(s),每次從優先佇列中bfs之前取出的用來擴充套件的就是當前最小距離,因為最短距離一定<=真實距離,所以可以:
1、用終點t作為dijkstra的起點在反向圖中跑一遍dijkstra算出每個點到終點的最短距離,作為那個點的估值。
2、用astar演算法,然後根據估值排序(把估計值作為pair的first放到優先佇列就可以實現按估值排序了),從s開始bfs,每次的取出的就是最短,第k次到達t點就是第k短路了。
完整**:
#include #include #include #define pll pair#define plll pair#define x first
#define y second
using namespace std;
const int maxm=2e5+5,maxn=1e3+5;
int head[maxn],e[maxm],net[maxm],w[maxn],to[maxm],rhead[maxn];
int s,t,k;
int cnt,n,m,dis[maxn],vis[maxn],f[maxn];//f[i]記錄到達編號為i的點估計的距離(本題取的最短距離),所以f=dis
void addedge(int *head,int a,int b,int l)
void dijkstra()
);//從終點開始往回擴充套件,由此計算出每個點距離t的最短距離作為估值f
dis[t]=0;//dijkstra演算法,起點的dis初始值為0!
while(heap.size())});//first存放當前點的估值f(估計距離),priority_queue按first這個估計值排序(從小到大),second.first為當前點的真實距離,second.second為當前點的編號
while(heap.size())});//每次擴充套件時,當前最短距離+邊權+估值作為下一次的估值,當前真實距離d+w[i],當前點編號v}}
return -1;
}int main()
scanf("%d%d%d",&s,&t,&k);
if(s==t) k++;//當s==t時,最短是自己到自己的,但該方案沒有邊,這裡不算做一條最短路,所以除去這條,下條最短算作第一短,應該是求k+1短
dijkstra();
int ans=astar();
cout
}
第K短路(A 演算法)
對於無向圖 spfa a 演算法 先用spfa求目標結點到各個結點的最短路徑 然後,取g x 為從初始結點到當前結點x的路徑長度,h x 為從x結點到目標結點的最短路徑長度,即h x 取dis x 即可,估價函式f x g x h x 對於有向圖 spfa a 演算法 顯然應將有向邊取反,然後求目標...
第K短路 嚴格第K短路
所謂k短路,就是從s到t的第k短的路,第1短就是最短路。如何求第k短呢?有一種簡單的方法是廣度優先搜尋,記錄t出佇列的次數,當t第k次出佇列時,就是第k短路了。但點數過大時,入佇列的節點過多,時間和空間複雜度都較高。a 是在搜尋中常用的優化,一種啟發式搜尋。簡單的說,它可以用公式表示為f n g n...
A 演算法求第k短路徑
a 演算法是一類貪心演算法,其可以用於尋找最優路徑。我們可以利用a 演算法來求第k短路徑。一條路徑可以由兩部分組成,第一部分是乙個從出發到達任意點的任意路徑,而第二部分是從第一部分的末端出發,到終點的最短路徑。兩部分正好可以組成一條路徑,且每一條路徑都可以分解這兩部分 允許任意一部分為空 因此當我們...