有 n 個城市、m 條雙向道路,油箱容量 C。部分城市有加油站(到達即滿油),部分城市可買賣燃油(價格 money[i])。從 1 出發到 n,求最大獲利(賣油收入 - 買油成本),油耗為路長。
dis[n] > C 則無解(-1)。記錄 dis1[i] = 1 到 i 的最小油耗。n 出發跑最短路,同樣處理加油站。記錄 dis2[i] = i 到 n 的最小油耗。i,若 dis1[i] ≤ C 且 dis2[i] ≤ C,則往返可行。油箱容量 C,去程耗 dis1[i],回程耗 dis2[i],剩餘 C - dis1[i] - dis2[i] 可賣油,獲利 = 剩餘 * money[i]。取最大值。#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5005, MAXM = 200005;
struct Edge { int v, w, next; } e[MAXM];
int head[MAXN], dis[MAXN], fuel[MAXN], money[MAXN];
bool inq[MAXN];
int n, m, C, ecnt;
void add_edge(int u, int v, int w) {
e[ecnt] = {v, w, head[u]};
head[u] = ecnt++;
}
void spfa(int s) {
fill(dis, dis+n+1, 0x3f3f3f3f);
fill(inq, inq+n+1, false);
queue q;
dis[s] = 0; q.push(s); inq[s] = true;
while (!q.empty()) {
int u = q.front(); q.pop(); inq[u] = false;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if (dis[u] + w > C) continue; // 油不夠
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (fuel[v]) dis[v] = 0; // 加油站歸零
if (!inq[v]) { q.push(v); inq[v] = true; }
}
}
}
}
int main() {
while (cin >> n >> m >> C) {
fill(head, head+n+1, -1);
fill(fuel, fuel+n+1, 0);
fill(money, money+n+1, 0);
ecnt = 0;
vector> edges;
for (int i=0;i>a>>b>>d;
edges.emplace_back(a,b,d);
add_edge(a,b,d);
}
int k; cin>>k;
while (k--) { int x; cin>>x; fuel[x]=1; }
cin>>k;
while (k--) { int x,p; cin>>x>>p; money[x]=p; }
spfa(1);
if (dis[n] > C) { cout << -1 << '\n'; continue; }
vector dis1(dis, dis+n+1);
// 反向圖
fill(head, head+n+1, -1); ecnt = 0;
for (auto [a,b,d] : edges) add_edge(b,a,d);
spfa(n);
vector dis2(dis, dis+n+1);
int ans = 0;
for (int i=1;i<=n;++i) if (money[i] && dis1[i]<=C && dis2[i]<=C)
ans = max(ans, (C - dis1[i] - dis2[i]) * money[i]);
cout << ans << '\n';
}
return 0;
}
dis[u] + w ≤ C,否則該邊不可通行。