1. 程式人生 > >A*與K短路

A*與K短路

A*演算法

一般的搜尋有兩種:BFS或DFS。這兩種搜尋都有一個特點,就是搜尋順序與每個節點與起點的距離有關,但是,這樣搜尋的節點很多是沒有必要的,在現實中,我們在走下一步時,還要考慮下一步到終點的距離,A演算法就是在普通的BFS中加一個估價函式,對下一步到終點的距離進行估計,優先搜尋到起點的距離與到終點距離的估價值的和小的節點,設想一下,如果估價函式就是當前點到終點的距離,那麼這個搜尋每一步走的都是最優解,但是,由於估價函式只是預先估計,一般不可能做到完全等於現實中的距離,但是這樣也比直接搜尋優秀。一般來說,如果是在矩陣中,那麼估價函式可以用曼哈頓距離。由於複雜度完全取決於估價函式的好壞(越接近真實距離越好),所以A

演算法的時間複雜度於空間複雜度都是玄學。

K短路

求最短路很簡單,求次短路也很簡單(只要把最短路上的某一條邊去掉後再重新刷最短路,所有的值中最小的就是次短路),但是要求k短路好像就有點麻煩了。
設想一下,如果A*的估價函式完全與真實距離相等,那麼每一次搜尋到終點都是當前最優的,所以第k次搜尋到終點的距離就是k短路了。估價函式完全可以預處理,只要把所有的邊倒過來,然後從終點開始刷最短路,從終點到每個點的距離就是那個點的估價函式。
模板題:POJ 2449
程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue> #define maxn 1006 #define maxe 100006 using namespace std; inline char nc(){ static char buf[100000],*i=buf,*j=buf; return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++; } inline int _read(){ char ch=nc();int sum=0; while(!(ch>='0'&&ch<='9'))ch=nc(); while
(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc(); return sum; } int n,e,ans,S,T,K,hed,tal,tot[2],que[maxn],dis[maxn],lnk[2][maxn],nxt[2][maxe],son[2][maxe],w[2][maxe]; bool vis[maxn]; struct data{ int x,g; data(int X,int G){x=X,g=G;} bool operator <(const data&b)const{ return g+dis[x]>b.g+dis[b.x]; } }; priority_queue<data> heap; void add(int p,int x,int y,int z){ nxt[p][++tot[p]]=lnk[p][x];son[p][tot[p]]=y;w[p][tot[p]]=z;lnk[p][x]=tot[p]; } void spfa(){ memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis)); hed=0;que[tal=1]=T;vis[T]=1;dis[T]=0; while(hed!=tal){ hed=(hed+1)%maxn;vis[que[hed]]=0; for(int j=lnk[1][que[hed]];j;j=nxt[1][j]) if(dis[son[1][j]]>dis[que[hed]]+w[1][j]){ dis[son[1][j]]=dis[que[hed]]+w[1][j]; if(!vis[son[1][j]]){ vis[son[1][j]]=1; que[tal=(tal+1)%maxn]=son[1][j]; if(dis[que[tal]]<dis[que[(hed+1)%maxn]])swap(que[tal],que[(hed+1)%maxn]); } } } } void A_star(){ while(!heap.empty())heap.pop(); heap.push(data(S,0)); while(!heap.empty()){ data x=heap.top();heap.pop(); if(x.x==T&&(!(--K))){ printf("%d",x.g); return; } for(int j=lnk[0][x.x];j;j=nxt[0][j])heap.push(data(son[0][j],x.g+w[0][j])); } } int main(){ freopen("dist.in","r",stdin); freopen("dist.out","w",stdout); n=_read();e=_read(); for(int i=1,x,y,z;i<=e;i++)x=_read(),y=_read(),z=_read(),add(0,x,y,z),add(1,y,x,z); S=_read();T=_read();K=_read();if(S==T)K++; spfa();A_star(); if(K)printf("-1"); return 0; }