在处理好输入输出之后,关键从集合的角度考虑最小花费。
决策类问题带有动态规划的思想,用第一个维度表示从起点到达的城市,第二个维度表示当前油箱剩余的油量,f[i,j]表示从起点到i城剩余油量为j的最小花费。
然后使用一个小根堆来维护这个状态,这样可以保证第一次得到终点时的状态是最优解
这道题难在无法判断在某个城市应该加多少油,因此我们一点一点的加。每次加一单位的油并加入优先队列,直到到达终点即可,剩下的就很像最短路里的堆优化dijkstra了
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define N 1010
#define M 10010
int n,m;
int S,T,c;
int pi[M];
int e[M*2],ne[M*2],h[N],w[2*M],idx=0;
int f[N][N]; //动态规划用
bool st[N][110];
struct Cost{
int city,fl,s; //到达的城市,剩余的油量,花费
bool operator<(const Cost W)const{
return W.s<s;
}
};
void add(int a,int b,int c){
e[idx]=b,w[idx]=c;
ne[idx]=h[a],h[a]=idx++;
}
int bfs(int S,int T,int c){
memset(st,0,sizeof st);
memset(f,0x3f,sizeof f);
priority_queue<Cost> heap;
heap.push({S,0,0});
f[S][0]=0;
while(heap.size()){
auto u=heap.top();heap.pop();
int city = u.city , fuel = u.fl , spent = u.s ;
if(st[city][fuel]) continue;
st[city][fuel]=true;
if(city==T){
return spent;
}
for(int i=h[city];~i;i=ne[i]){
int j=e[i];
if(fuel>=w[i]&&f[city][fuel]<f[j][fuel-w[i]]){
f[j][fuel-w[i]]=f[city][fuel];
heap.push({j,fuel-w[i],f[j][fuel-w[i]]});
}
}
if(fuel<c){
if(f[city][fuel]+pi[city]<f[city][fuel+1]){
f[city][fuel+1]=f[city][fuel]+pi[city];
heap.push({city,fuel+1,f[city][fuel+1]});
}
}
}
return -1;
}
int main(){
memset(h,-1,sizeof h);
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&pi[i]);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
int q;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&c,&S,&T);
int res=bfs(S,T,c);
if(res==-1) puts("impossible");
else printf("%d\n",res);
}
return 0;
} 
京公网安备 11010502036488号