题目链接:https://vjudge.net/problem/UVA-11367
题目大意:
给出n个地点 和 每个地点的油价 ,有 m 条边 , 并给出每条边长度 。1单位汽油可以走1千米 , 油箱的容量为 c , 在初始点 s 时 , 油箱中的油为 0 , 求s 到 t 的最小花费 。
思路:
因为并不能确定这个点是否需要加油,这不是一个单调性的问题,所以需要dp一下,用分层图的思想,dis[i][j]表示到达i这个点邮
箱内还有j升油的最小花费,那么就是一个很裸的分层图了,对于每个点,遍历每条边时可以加多少油都是一种状态。
但是!如果你暴力的加所有的状态的话,毫无疑问会超时,因为Heap中的节点实在是太多了,而有用的节点没有多少个。
所以,就像之前任意起点终点k短路那样,我们并不需要加所有的状态,而是像分层图那样,在当前节点u一升一升地加油,如果可
以走哪条边的就转移过去。这样可以避免很多没有用的节点,也就不会超市了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int maxn=1000+10;
struct Edge{
int from,to,cost;
Edge(int u,int v,int cost):from(u),to(v),cost(cost){}
};
vector<int>G[maxn];
vector<Edge>edges;
int p[maxn];//油价
ll dis[maxn][110];//表示到达i点还剩j升油的最小花费
int vis[maxn][110];
int n,m;
const ll INF=0x3f3f3f3f3f3f;
struct HeapNode{
int u;
ll d;
int c;
HeapNode(int u,ll d,int c):u(u),d(d),c(c){}
bool operator < (const HeapNode &rhs)const{
return d>rhs.d;
}
};
void add_edges(int u,int v,int cost){
edges.push_back(Edge(u,v,cost));
edges.push_back(Edge(v,u,cost));
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
ll Dijkstra(int s,int t,int c){
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++){
for(int j=0;j<=c;j++){
dis[i][j]=INF;
}
}
priority_queue<HeapNode>Q;
Q.push(HeapNode(s,0,0));
vis[s][0]=1;
dis[s][0]=0;
while(Q.size()){
HeapNode x=Q.top();Q.pop();
int u=x.u;
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(x.c>=e.cost){//可以转移
if(dis[e.to][x.c-e.cost]>dis[u][x.c]){
dis[e.to][x.c-e.cost]=dis[u][x.c];
if(!vis[e.to][x.c-e.cost]){
Q.push(HeapNode(e.to,dis[e.to][x.c-e.cost],x.c-e.cost));
vis[e.to][x.c-e.cost]=1;
}
}
}
}
if(x.c<c){
if(dis[u][x.c+1]>dis[u][x.c]+p[u]){
dis[u][x.c+1]=dis[u][x.c]+p[u];
if(!vis[u][x.c+1]){
Q.push(HeapNode(u,dis[u][x.c+1],x.c+1));
}
}
}
}
ll ans=INF;
for(int i=0;i<=c;i++){
ans=min(ans,dis[t][i]);
}
return ans;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=0;i<n;i++){
scanf("%lld",&p[i]);
}
for(int i=1;i<=m;i++){
int u,v,cost;
scanf("%lld%lld%lld",&u,&v,&cost);
add_edges(u,v,cost);
}
int q;
for(scanf("%lld",&q);q--;){
int s,t,c;
scanf("%lld%lld%lld",&c,&s,&t);
ll ans=Dijkstra(s,t,c);
if(ans==INF){
puts("impossible");
}
else{
printf("%lld\n",ans);
}
}
return 0;
}