第K短路+严格第K短路
??所謂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,gv)-->(U,fu+w[v][u],gv+w[v][u])。
????5. 終止條件。每個節點最多入隊列K次,當t出隊列K次時,即找到解。
?
????例:POJ2449
????題意:裸的K短路。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 1005; int n,m; int start,end,k; struct Edge {int w;int to;int next; }; Edge e[100005]; int head[MAX],edgeNum; int dis[MAX]; ? //dis[i]表示從i點到end的最短距離 bool vis[MAX]; int cnt[MAX]; vector<Edge> opp_Graph[MAX];struct Node {int f,g; ? ?//f = g+dis[v]int v; ? ? ?//當前到達的節點Node(int a, int b,int c):f(a),g(b),v(c){}bool operator < (const Node& a) const{return a.f < f;} };void addEdge(int from, int to, int w) {e[edgeNum].to = to;e[edgeNum].w = w;e[edgeNum].next = head[from];head[from] = edgeNum++; }void dijikastra(int start) {int i;memset(vis,0,sizeof(vis));for(i = 1; i <= n; i++)dis[i] = INF;dis[start] = 0;priority_queue<Node> que;que.push(Node(0,0,start));Node next(0,0,0);while(!que.empty()){Node now = que.top();que.pop();if(vis[now.v]) ? ? ? ? ? ? ?//從集合T中選取具有最短距離的節點continue;vis[now.v] = true; ? ? ? ? ?//標記節點已從集合T加入到集合S中for(i = 0; i < opp_Graph[now.v].size(); i++) ? ?//更新從源點到其它節點(集合T中)的最短距離{Edge edge = opp_Graph[now.v][i];if(!vis[edge.to] && dis[now.v] + edge.w < dis[edge.to]) ? ? //加不加前面的判斷無所謂{dis[edge.to] = dis[now.v] + edge.w;next.f = dis[edge.to];next.v = edge.to;que.push(next);}}} }int A_Star() {int i;priority_queue<Node> que;if(dis[start] == INF)return -1;que.push(Node(dis[start],0,start));Node next(0,0,0);while(!que.empty()){Node now = que.top();que.pop();cnt[now.v]++;if(cnt[end] == k) return now.f;//嚴格最短路的判斷條件為 cnt[end] == k&&now.f>min(zuiduanlu)if(cnt[now.v] > k)continue;for(i = head[now.v]; i != -1; i = e[i].next){next.v = e[i].to;next.g = now.g + e[i].w;next.f = next.g + dis[e[i].to];que.push(next);}}return -1; }int main() {int i;int from,to,w;edgeNum = 0;memset(head,-1,sizeof(head));memset(opp_Graph,0,sizeof(opp_Graph));memset(cnt,0,sizeof(cnt));scanf("%d %d",&n,&m);Edge edge;for(i = 1; i <= m; i++){scanf("%d %d %d",&from,&to,&w);addEdge(from,to,w);edge.to = from;edge.w = w;opp_Graph[to].push_back(edge);}scanf("%d %d %d",&start,&end,&k);if(start == end)k++;dijikastra(end);int result = A_Star();printf("%d\n",result);return 0; }?
總結
以上是生活随笔為你收集整理的第K短路+严格第K短路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷P3360偷天换日(树形DP)
- 下一篇: vue的开发工具都有哪些呢