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;
}