1. 程式人生 > >【模板】BZOJ1975: [Sdoi2010]魔法豬學院-A*演算法-k短路

【模板】BZOJ1975: [Sdoi2010]魔法豬學院-A*演算法-k短路

題解

啟發式搜尋中的估價函式/A*演算法
先跑一遍節點n的最短路
此題中用小根堆維護(fi,i)
fi=gi+hi
這裡的hi就是當前點到目標節點n的最短路距離。gi是起點到當前點的目前狀態所走過的路徑長度。

程式碼

 #include<cstdio>
#include<algorithm>
#include<cctype>
#include<queue>
#define db double
using namespace std;
const int N=5e3+10,M=2e5+10,H=5e6
+10; const db inf=100000000.0,eps=1e-6; int n,m,ans; int head[2][N],to[2][M],nxt[2][M],tot; int vis[N],in[H],cnt;db w[M],E,f[H],dis[N]; queue<int>Q; inline int rd() { char ch=getchar();int x=0,f=1; while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();} return
x*f; } inline void lk(int u,int v,db c){ to[0][++tot]=v;nxt[0][tot]=head[0][u];head[0][u]=tot; to[1][tot]=u;nxt[1][tot]=head[1][v];head[1][v]=tot; w[tot]=c; } inline void spfa() { int x,i,j; dis[n]=0.0; for(i=1;i<n;++i) dis[i]=inf; Q.push(n);vis[n]=1; while(!Q.empty()){ x=Q.front();Q.pop();vis[x]=0
; for(i=head[1][x];i;i=nxt[1][i]){ j=to[1][i]; if(dis[j]>dis[x]+w[i]){ dis[j]=dis[x]+w[i]; if(!vis[j]){vis[j]=1;Q.push(j);} } } } } inline void pu(db val,int tag) { int x=++cnt,fa=x>>1; in[cnt]=tag;f[cnt]=val; while(fa && f[fa]>val){ swap(f[fa],f[x]);swap(in[fa],in[x]); x=fa;fa=fa>>1; } } inline void po() { swap(f[1],f[cnt]);swap(in[1],in[cnt]);cnt--; int x=1,y=x<<1;if(f[y|1]<f[y] && y<cnt) y|=1; while(y<=cnt && f[y]<f[x]){ swap(f[y],f[x]);swap(in[y],in[x]); x=y;y=x<<1;if(f[y|1]<f[y] && y<cnt) y|=1; } } inline void astar() { int i,j,x;db d; pu(dis[1],1); while(cnt){ x=in[1];d=f[1]; po(); if(x==n){E-=d;if(E>=eps) ans++;else return;} for(i=head[0][x];i;i=nxt[0][i]){ j=to[0][i]; pu(d-dis[x]+w[i]+dis[j],j); } } } int main(){ int i,j,ix,iy;db iz; n=rd(),m=rd();scanf("%lf",&E); for(i=1;i<=m;++i){ix=rd();iy=rd();scanf("%lf",&iz);lk(ix,iy,iz);} spfa(); astar(); printf("%d\n",ans); }