鏈接:http://poj.org/problem?id=2449
題意:告訴你有n個頂點,m條邊,并把這些邊的信息告訴你:起點、終點、權值。再告訴你s、t、k。需求出s到t的第k短路,沒有則輸出-1。
第K短路裸題,A*算法沒接觸過,參考了這篇博客:http://www.cnblogs.com/n-u-l-l/archive/2012/07/29/2614194.html
下面大體字摘自這篇博文,講的非常清楚:
對于第k短路,能夠想到的一個比較樸素的算法就是廣度優先搜索,使用優先隊列從源點s進行廣搜。當第k次搜索到終點t時,所得長度即所求可是這樣的方法在執行過程中會產生特別多的狀態。當圖比較簡單、k比較小時,能夠一試。可是當k較大或者圖中點數較多時。會面臨爆棧的危急。
眼下使用比較多的算法是單源最短路配合A*。A*是搜索中比較高級的方式,A*算法結合了啟示式方法(這樣的方法通過充分利用圖給出的信息來動態的作出決定而使搜索次數大大減少)和形式化方法(這樣的方法不利用圖給出的信息,而僅通過數學的形式分析,如Dijkstra算法)。
它通過一個估價函數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)須要在搜索之前進行預處理,僅僅要將原圖的全部邊反向。再從終點t做一次單源最短路就可以得到h(p)。單源最短路求法有Dijkstra,Bellman-Ford,SPFA等。
詳細步驟:
這里我們使用鏈式前向星來存儲如圖。因為須要預處理全部點到終點的最短路,就須要將圖G中全部邊反向得到圖G',再從終點t做一次單源最短路,所以實際上就是兩張圖。
(1)將有向圖的全部邊反向(無向圖能夠省略此步),以原圖終點t為源點做一次單源最短路,結果記入數組dis[i]中,dis[i]即為原圖中點i到點t的最短距離。
這里的dis[i]即上述的h(p);
(2)新建一個優先隊列。將源點s增加到隊列中。
(3)從優先隊列中彈出f(p)最小的點p(這里假設存在f(p)相等的點,則彈出g(p)最小的點),假設點p就是終點t,則計算t出隊列的次數,假設當前為t的第k次出隊。則當前路徑長度就是s到t的第k短路。算法結束。否則遍歷與p相連的全部的邊,將擴展出的到p的鄰接點信息增加到優先隊列。
值得注意的是。當s==t時須要計算(k+1)短路。由于s到t這條距離為0的路不能算在這k短路中,這時僅僅需將k自增1后再求第k短路就可以。
這道題比較坑的地方就是上面說的 s==t時須要計算(k+1)短路。m==0時也即s==t時。k+1短路不存在。應輸出-1。還有就是dist[s]!=INF時。盡管A*能找到最短路,但假設k較大。不一定存在第k短路。所以應當有個標記。我忘記加標記多WA了一發
#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1struct NODE{int u;int f,g;bool operator < (const NODE &t) const{if(t.f==f) return t.g > g;return t.f < f;}
};
struct EDGE{int u,w,next;
};
struct NODE2{int u,dis;bool operator < (const NODE2 &t) const{return t.dis < dis;}
};
EDGE edge[MAXN],redge[MAXN];
int head[1010],rhead[1010],vis[1010],dist[1010];
int n,m,cnt,rcnt,ans,flag;
void add_edge(int a,int b,int c){edge[cnt].u = b;edge[cnt].w = c;edge[cnt].next = head[a];head[a] = cnt++;redge[rcnt].u = a;redge[rcnt].w = c;redge[rcnt].next = rhead[b];rhead[b] = rcnt++;
}
void dijkstra_heap(int v){NODE2 t1,t2;int i,j;for(i=1;i<=n;i++) dist[i] = INF;dist[v] = 0;t1.u = v;t1.dis = 0;priority_queue<NODE2>q;q.push(t1);while(!q.empty()){t1 = q.top();q.pop();if(vis[t1.u]) continue;vis[t1.u] = 1;for(i=rhead[t1.u];i!=-1;i=redge[i].next){int x = redge[i].w;if(dist[t1.u]+x<dist[redge[i].u]){dist[redge[i].u] = x + dist[t1.u];t2.dis = dist[redge[i].u];t2.u = redge[i].u;q.push(t2);}}}
}
void Astar(int s,int t,int k){int i,j=0;NODE t1,t2;priority_queue<NODE>q;t1.u = s;t1.g = 0;t1.f = t1.g + dist[s];q.push(t1);while(!q.empty()){t1 = q.top();q.pop();if(t1.u==t) j++;if(j==k){ans = t1.f;flag = 1; //沒加標記。WA出翔return ;}for(i=head[t1.u];i!=-1;i=edge[i].next){t2.u = edge[i].u;t2.g = t1.g + edge[i].w;t2.f = t2.g + dist[t2.u];q.push(t2);}}
}
int main(){int i,j;int s,t,k;int a,b,c;while(scanf("%d%d",&n,&m)!=EOF){memset(head,-1,sizeof(head));memset(rhead,-1,sizeof(rhead));memset(vis,0,sizeof(vis));cnt = rcnt = 0;ans = 0;flag = 0;for(i=0;i<m;i++){scanf("%d%d%d",&a,&b,&c);add_edge(a,b,c);}scanf("%d%d%d",&s,&t,&k);if(s==t) k++;dijkstra_heap(t);if(dist[s]==INF&&m==0){puts("-1");continue;}Astar(s,t,k);if(!flag) puts("-1");else printf("%d\n",ans);}return 0;
}
轉載于:https://www.cnblogs.com/claireyuancy/p/6906746.html
總結
以上是生活随笔為你收集整理的POJ--2449--Remmarguts#39; Date【dijkstra_heap+A*】第K短路的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。