BZOJ-1975: 魔法猪学院 (K短路:A*+SPFA)
题意:有N种化学元素,有M种转化关系,(u,v,L)表示化学物质由u变为v需要L能量,现在你有E能量,问最多有多少种不同的途径,使得1转为为N,且总能量不超过E。
思路:可以转为为带权有向图,即是求前K(K未知)短路,满足前K短路的边权和小于等于E,求K。
BZOJ上面提交的时间和空间都还不错。但是洛谷卡空间,我一顿操作还是没卡过去。
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define uint unsigned short int #define rep(i,a,b) for(register int i=a;i<=b;i++) using namespace std; const int maxn=5010; const int maxm=200010; const double inf=0x7fffffff; int Laxt1[maxn],Next1[maxm],cnt1; uint To1[maxm],To2[maxm]; int Laxt2[maxn],Next2[maxm],cnt2; double dis[maxn],Len1[maxm],Len2[maxm]; int N,M,vis[maxn],ans; double E; void read(int &x){ x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); } struct in{ uint x; float f; in(){} in(uint xx,float ff):x(xx),f(ff){}; friend bool operator <(in w,in v){ return w.f+dis[w.x]>v.f+dis[v.x]; } }; void add(int u,int v,double L) { Next1[++cnt1]=Laxt1[u]; Laxt1[u]=cnt1; To1[cnt1]=v; Len1[cnt1]=L; Next2[++cnt2]=Laxt2[v]; Laxt2[v]=cnt2; To2[cnt2]=u; Len2[cnt2]=L; } uint q1[5010]; int head=0,tail=0; void dijkstra() { rep(i,1,N-1) dis[i]=inf; q1[++head]=N; while(head!=tail){ tail++; if(tail==N+1) tail=1; uint u=q1[tail]; vis[u]=0; for(int i=Laxt2[u];i;i=Next2[i]){ uint v=To2[i]; if(dis[v]>dis[u]+Len2[i]){ dis[v]=dis[u]+Len2[i]; if(!vis[v]){ vis[v]=1; head++; if(head==N+1) head=1; q1[head]=v; } } } } } void Astar(int K) { priority_queue<in>q; rep(i,1,N) vis[i]=0; q.push(in(1,0)); while(!q.empty()){ in T=q.top();q.pop(); if(T.f>E) return ; int u=T.x; vis[u]++; if(u==N){ E-=T.f; if(E<0) return ; ans++; continue; } if(vis[u]>=K) continue; for(int i=Laxt1[u];i;i=Next1[i]){ int v=To1[i]; q.push(in(v,T.f+Len1[i])); } } } int main() { scanf("%d%d%lf",&N,&M,&E); int u,v; double L; rep(i,1,M) { read(u); read(v); scanf("%lf",&L); add(u,v,L); } dijkstra(); Astar(E/dis[1]+1); printf("%d\n",ans); return 0; }
It is your time to fight!