用二元组$(city,fuel)$即可记录所有状态,以当前花费为关键字优先队列,开数组记录直接做即可
有一个点在于每次不用枚举所有的加油数量,只需要加一即可,因为如果在加一升更优的话又会扩展出加更多油的状态,不必枚举过多
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int maxn=1009; const int maxm=10009; int n,m,a[maxn],c; struct node{ int v,w,nxt; }e[maxm*2]; struct now{ int x,r,c;//当前城市,剩余油量,花费 now(){} now(int xx,int rr,int cc){ x=xx,r=rr,c=cc; } bool operator <(const now&a)const{ return c>a.c; } }; int head[maxn],cnt; int d[maxn][109],v[maxn][109]; inline void add(int u,int v,int w){ e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt; } priority_queue<now>q; int bfs(int st,int ed){ while(!q.empty())q.pop(); memset(d,0x3f,sizeof(d)); memset(v,0,sizeof(v)); q.push(now(st,0,0));d[st][0]=0; while(!q.empty()){ now x=q.top();q.pop(); v[x.x][x.r]=1; if(x.x==ed)return x.c; if(!v[x.x][x.r+1] && x.r+1<=c && !v[x.x][x.r+1] &&(d[x.x][x.r+1]>d[x.x][x.r]+a[x.x])){ d[x.x][x.r+1]=d[x.x][x.r]+a[x.x]; q.push(now(x.x,x.r+1,x.c+a[x.x])); } for(int i=head[x.x];i;i=e[i].nxt){ int y=e[i].v,z=e[i].w; if(x.r-z>=0 && !v[y][x.r-z] && d[y][x.r-z]>x.c){ d[y][x.r-z]=x.c; q.push(now(y,x.r-z,x.c)); } } } return -1; } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++)scanf("%d",&a[i]); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } int Q; scanf("%d",&Q); for(int i=1,st,ed;i<=Q;i++){ scanf("%d%d%d",&c,&st,&ed); int ans=bfs(st,ed); if(ans!=-1) printf("%d ",ans); else printf("impossible "); } }