版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84312761
思路分析:
考虑使用优先队列BFS, 解空间树中的每个状态对应一个三元组(i, j, k), 表示从城市i出发时剩余油量为j升的最小花费为k, 对于每一个状态三元组Q如果j < c, (c为油箱容量) 那么可从Q扩展至状态(i, j + 1, p), 如果u与i之间存在长度为d的路, 且j >= d, 那么可从Q扩展至状态(u, j - d, r), 具体实现如下AC代码所示:
//POJ3635_Full Tank?
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <deque>
#include <algorithm>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
const int MAXN = 1e3 + 5, MAXM = 1e4 + 5, MAXC = 105, NIL = 0x3f3f3f3f;
int n, m, pr[MAXN], d[MAXN][MAXC];//d[i][j]:到达城市i, 剩余j单位油的最小费用, pr[i]:城市i的油价
int head[MAXN], ver[MAXM * 2 + 5], nex[MAXM * 2 + 5], we[MAXM * 2 + 5], tot;
struct cmp{
bool operator()(const pair<int, pii> &a, const pair<int, pii> &b){
return a.fi > b.fi;
}
};
int main(){
scanf("%d %d", &n, &m);
for(int i = 0; i < n; ++i) scanf("%d", &pr[i]);
for(int i = 1, u, v, w; i <= m; ++i){
scanf("%d %d %d", &u, &v, &w);
if(!head[u]) ver[++tot] = v, head[u] = tot, we[tot] = w;
else ver[++tot] = v, we[tot] = w, nex[tot] = head[u], head[u] = tot;
if(!head[v]) ver[++tot] = u, head[v] = tot, we[tot] = w;
else ver[++tot] = u, we[tot] = w, nex[tot] = head[v], head[v] = tot;
}
int q; scanf("%d", &q);
while(q--){
int c, s, e; scanf("%d %d %d", &c, &s, &e); memset(d, 0x3f, sizeof(d));
priority_queue<pair<int, pii>, vector<pair<int, pii> >, cmp> pq;
pq.push(mp(0, mp(s, 0))), d[s][0] = 0; int res = NIL;
while(!pq.empty()){
int fi = pq.top().se.fi, se = pq.top().se.se, w = pq.top().fi; pq.pop();
if(fi == e){
res = w; break;
}
//本城市加油
if(se < c && d[fi][se] + pr[fi] < d[fi][se + 1])
d[fi][se + 1] = d[fi][se] + pr[fi], pq.push(mp(d[fi][se + 1], mp(fi, se + 1)));
//到相邻城市加油
for(int i = head[fi]; i; i = nex[i])
if(se >= we[i] && d[fi][se] < d[ver[i]][se - we[i]])
d[ver[i]][se - we[i]] = d[fi][se]
, pq.push(mp(d[ver[i]][se - we[i]], mp(ver[i], se - we[i])));
}
if(res == NIL) cout << "impossible" << endl; else cout << res << endl;
}
return 0;
}