1. 程式人生 > >POJ - 2449 Remmarguts' Date (k短路)(A*)

POJ - 2449 Remmarguts' Date (k短路)(A*)

題意:求有向圖從s點到t點的第k短路,每個點可以重複經過。

解法:建一個正向圖和一個反向圖,先用Dijkstra求出反向圖中從t點到其他點的最短距離dis,再用A*演算法求出第k短路。

A*求第k短路的方法:與Dijkstra演算法類似,設結點nd(u,g)表示當前所在點為u且從s到u經過的長度為g的結點(路徑),則以g+dis[u]為權值放進優先佇列,每次選擇權值最小的結點進行擴充套件,直至t點第k次出隊。

算是A*演算法的一道入門題吧。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4
5 using namespace std; 6 const int N=1000+10,M=1e5+10; 7 const int inf=0x3f3f3f3f; 8 struct E { 9 int v,c,nxt; 10 } e[M<<1]; 11 int head1[N],head2[N],dis[N],vis[N],ne; 12 int n,m; 13 14 struct cmp { 15 bool operator()(int a,int b)const { 16 return dis[a]>dis[b];
17 } 18 }; 19 20 struct nd { 21 int u,g; 22 bool operator<(const nd& b)const { 23 return g+dis[u]>b.g+dis[b.u]; 24 } 25 }; 26 27 void Dij(int s) { 28 priority_queue<int,vector<int>,cmp> q; 29 memset(vis,0,sizeof vis); 30 memset(dis,inf,sizeof
dis); 31 dis[s]=0; 32 q.push(s); 33 while(!q.empty()) { 34 int u=q.top(); 35 q.pop(); 36 if(vis[u])continue; 37 vis[u]=1; 38 for(int i=head2[u]; ~i; i=e[i].nxt) { 39 int v=e[i].v,c=e[i].c; 40 if(dis[u]+c<dis[v]) { 41 dis[v]=dis[u]+c; 42 q.push(v); 43 } 44 } 45 } 46 } 47 48 int Astar(int s,int t,int k) { 49 int cnt=0; 50 if(s==t)cnt--; 51 priority_queue<nd> q; 52 q.push({s,0}); 53 while(!q.empty()) { 54 int u=q.top().u,g=q.top().g; 55 q.pop(); 56 if(u==t)++cnt; 57 if(cnt==k)return g; 58 for(int i=head1[u]; ~i; i=e[i].nxt) { 59 int v=e[i].v,c=e[i].c; 60 q.push({v,g+c}); 61 } 62 } 63 return -1; 64 } 65 66 int main() { 67 memset(head1,-1,sizeof head1); 68 memset(head2,-1,sizeof head2); 69 ne=0; 70 scanf("%d%d",&n,&m); 71 while(m--) { 72 int u,v,c; 73 scanf("%d%d%d",&u,&v,&c); 74 e[ne]=(E) {v,c,head1[u]},head1[u]=ne++; 75 e[ne]=(E) {u,c,head2[v]},head2[v]=ne++; 76 } 77 int s,t,k; 78 scanf("%d%d%d",&s,&t,&k); 79 Dij(t); 80 printf("%d\n",Astar(s,t,k)); 81 return 0; 82 }