题目大意:n个点m条边的有向图,q次询问c,s,t,表示汽车邮箱容量为c,求从起点s到终点t的最小费用。汽车在每个点可以加任意的油,每个点的单位油价为a[i]。
题目思路:利用最小费优先队列优化最短路,dist[u][use]代表到达u节点,剩余use单位汽油的花费值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<iostream> #include<algorithm> #include<vector> #include<queue> #define MAXSIZE 1015 #define INF 0x3f3f3f3f #define LL long long using namespace std; typedef pair<int,int>p; typedef pair<p,int>pp; int dist[MAXSIZE][105],val[105],a[2*MAXSIZE],k; struct node { int u; int v; int w; int next; } G[2*MAXSIZE]; void Add(int u,int v,int w) { G[k].u=u; G[k].v=v; G[k].w=w; G[k].next=a[u]; a[u]=k++; } int spfa(int s,int t,int c) { memset(dist,INF,sizeof(dist)); priority_queue<pp,vector<pp>,greater<pp> >Q; dist[s][0]=0; Q.push(pp(p(dist[s][0],0),s)); // 按优先级顺序入队 while(!Q.empty()) { pp k=Q.top(); Q.pop(); int w=k.first.first; //已花费的钱 int use=k.first.second; //剩余油量 int u=k.second; //当前节点 if(w > dist[u][use]) continue; if(u==t) //最小费优先 return dist[u][use]; for(int i=a[u]; i!=-1; i=G[i].next) { int v=G[i].v; if(G[i].w > c) continue; if(use >= G[i].w && dist[v][use - G[i].w] > dist[u][use]) //当前剩余油量足够到达v { dist[v][use - G[i].w] = dist[u][use]; Q.push(pp(p(dist[v][use - G[i].w],use - G[i].w),v)); } } if(use < c)//当前油量不足以到达下一个点,就向邮箱里加1个单位的汽油 { dist[u][use+1] = dist[u][use] + val[u]; Q.push(pp(p(dist[u][use+1],use+1),u)); } } return INF; } void Init() { memset(a,-1,sizeof(a)); k=1; } int main() { int T,n,m,c,s,t,u,v,w,cns=1; scanf("%d",&T); while(T--) { Init(); scanf("%d%d",&n,&m); for(int i=0; i<n; i++) scanf("%d",&val[i]); for(int i=1; i<=m; i++) { scanf("%d%d%d",&u,&v,&w); Add(u,v,w); Add(v,u,w); } scanf("%d",&m); printf("Case %d: ",cns++); while(m--) { memset(dist,INF,sizeof(dist)); scanf("%d%d%d",&c,&s,&t); int ans=spfa(s,t,c); if(ans != INF) printf("%d ",ans); else printf("impossible "); } } return 0; }