所謂k短路,就是從s到t的第k短的路,第1短就是最短路。
如何求第k短呢?有一種簡單的方法是廣度優先搜尋,記錄t出佇列的次數,當t第k次出佇列時,就是第k短路了。但點數過大時,入佇列的節點過多,時間和空間複雜度都較高。
a*是在搜尋中常用的優化,一種啟發式搜尋。簡單的說,它可以用公式表示為f(n) = g(n) + f(n),其中,f(n)是從s經由節點n到t的估價函式,g(n)是在狀態空間中從s到n的實際代價,h(n)是從n到t的最佳路徑估計代價。在設計中,要保證h(n)<= n到t的實際代價,這一點很重要,h(n)越接近真實值,速度越快。
由於啟發函式的作用,使得計算機在進行狀態轉移時盡量避開不可能產生最優解的分支,而選擇相對較接近最優解的路徑進行搜尋,降低了時間和空間複雜度。
演算法過程:
1. 將圖反向,用dijstra+heap求出t到所有點的最短距離,目的是求所有點到點t的最短路,用dis[i]表示i到t的最短路,其實這就是a*的啟發函式,顯然:h(n)<= n到t的實際代價。
2. 定義估價函式。我們定義g(n)為從s到n所花費的代價,h(n)為dis[n],顯然這符合a*演算法的要求。
3. 初始化狀態。狀態中存放當前到達的點i,fi,gi。顯然,fi=gi+dis[i]。初始狀態為(s,dis[s],0),存入優先順序佇列中。
4. 狀態轉移。假設當前狀態所在的點v相鄰的點u,我們可以得到轉換:(v,fv,**)-->(u,fu+w[v][u],**+w[v][u])。
5. 終止條件。每個節點最多入佇列k次,當t出佇列k次時,即找到解。
例:poj2449
題意:裸的k短路。
#include #include #include #include using namespace std;
const int inf = 0x3f3f3f3f;
const int max = 1005;
int n,m;
int start,end,k;
struct edge
;edge e[100005];
int head[max],edgenum;
int dis[max]; //dis[i]表示從i點到end的最短距離
bool vis[max];
int cnt[max];
vectoropp_graph[max];
struct node
bool operator < (const node& a) const
}; void addedge(int from, int to, int w)
void dijikastra(int start)
}}}
int a_star()
}return -1;}
int main()
scanf("%d %d %d",&start,&end,&k);
if(start == end)
k++;
dijikastra(end);
int result = a_star();
printf("%d\n",result);
return 0;
}
第K短路(A 演算法)
對於無向圖 spfa a 演算法 先用spfa求目標結點到各個結點的最短路徑 然後,取g x 為從初始結點到當前結點x的路徑長度,h x 為從x結點到目標結點的最短路徑長度,即h x 取dis x 即可,估價函式f x g x h x 對於有向圖 spfa a 演算法 顯然應將有向邊取反,然後求目標...
第k短路和A
第一次接觸a 感覺好神奇。啟發函式 f x g x h x 比如初始狀態為s,目標狀態為t g x 表示從s到達狀態x所消耗的代價 h x 表示從x到達t所估算的代價 g x 表示s x可能出現的最小代價 h x 表示x t可能出現的最小代價 g x g x h x h x 好吧,上面全是概念。當g...
第K短路(模板)
沒太想明白 就當存在模板吧 include include include include include include include include include include using namespace std typedef long long ll const int maxn ...