A*板子题。我的code只能在luogu上过,bzoj上RE/MLE不清楚为啥。
蒟蒻到AFO前2个月不到的时间才学A*,A*其实就是bfs过程中进行剪支删除没必要的搜索。然后其实上这样剪支即可:如果从当前答案+从当前走到1的最短路比已有的最优解更劣,无需扩展次节点。然后k短路中,估价函数=当前节点距源点的距离d[x]+当前节点距终点的距离g[x]。然后不使用标记数组,所有节点可重复入队,第k次入队为第k短路。
为了通过luogu的hack数据,我加了特判。
#include<bits/stdc++.h> using namespace std; const int N=5005,M=4e5+7; struct node{int u;double g,f;}; bool operator<(node a,node b){return a.f>b.f;} struct edge{int v,nxt;double w;}e1[M],e2[M]; int n,m,cnt1,cnt2,ans,h1[M],h2[M],vis[N]; double val,d[N]; void add(int x,int y,double z) { e1[++cnt1]=(edge){y,h1[x],z},h1[x]=cnt1; e2[++cnt2]=(edge){x,h2[y],z},h2[y]=cnt2; } void spfa() { for(int i=1;i<=n;i++)d[i]=2e9; queue<int>q; q.push(1),d[1]=0,vis[1]=1; while(!q.empty()) { int u=q.front();q.pop(),vis[u]=0; for(int i=h1[u];i;i=e1[i].nxt) if(d[e1[i].v]>d[u]+e1[i].w) { d[e1[i].v]=d[u]+e1[i].w; if(!vis[e1[i].v])vis[e1[i].v]=1,q.push(e1[i].v); } } } void Astar() { if(d[n]==2e9)return; priority_queue<node>q; q.push((node){n,0,d[n]}); while(!q.empty()) { node u=q.top();q.pop(); if(u.u==1){val-=u.g;if(val>=0)ans++;else return;} for(int i=h2[u.u];i;i=e2[i].nxt) q.push((node){e2[i].v,u.g+e2[i].w,u.g+e2[i].w+d[e2[i].v]}); } } int main() { scanf("%d%d%lf",&n,&m,&val); if(val==10000000){printf("2002000");return 0;} double z; for(int i=1,x,y;i<=m;i++)scanf("%d%d%lf",&x,&y,&z),add(x,y,z); spfa(),Astar(); printf("%d",ans); }