HDU 3143:搶劫犯與警察同時從不同起點出發,搶劫犯速度可控,警察固定 160 km/h。搶劫犯需到達任意高速公路出口,且全程不被警察追上(同一時間同一地點即被捕)。求搶劫犯最小最高速度。
X,設搶劫犯距離 d_r(X),警察距離 d_p(X)d_r(X) / v_r < d_p(X) / 160 → v_r > 160 * d_r(X) / d_p(X)max(160 * d_r / d_p)P 到所有點的最短距離 dist_p[] (Dijkstra)B 到所有點的最短距離 dist_r[],**但必須繞過警察起點 P** (修改版 Dijkstra,禁止經過 P)pre[])E,若可達 (dist_r[E] < INF),回溯路徑 E → ... → Bu,計算所需速度 v_u = 160 * dist_r[u] / dist_p[u](若 dist_p[u] == INF 則警察不可達,速度為 0)v_uvector<int> pre(n+1, -1);
priority_queue<pair<double,int>, vector<pair<double,int>>, greater<>> pq;
dist[src] = 0;
pq.push({0, src});
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (d > dist[u]) continue;
for (auto [v, w] : adj[u]) {
if (v == police) continue; // 搶劫犯繞過警察起點
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pre[v] = u; // 記錄前驅
pq.push({dist[v], v});
}
}
}
double ans = INF;
for (int exit : exits) {
if (dist_r[exit] == INF) continue; // 不可達
double need = 0;
for (int u = exit; u != -1; u = pre[u]) {
if (dist_p[u] < INF) { // 警察可達此點
need = max(need, 160.0 * dist_r[u] / dist_p[u]);
}
}
ans = min(ans, need);
}
if (ans == INF) cout << "IMPOSSIBLE\n";
else cout << fixed << setprecision(10) << ans << '\n';
#include <bits/stdc++.h>
using namespace std;
const double INF = 1e100;
const int MAXN = 105;
struct Edge { int to, len; };
vector<Edge> adj[MAXN];
double dist_p[MAXN], dist_r[MAXN];
int pre[MAXN];
bool is_exit[MAXN];
void dijkstra(int src, double dist[], int avoid = -1) {
fill(dist, dist + MAXN, INF);
fill(pre, pre + MAXN, -1);
dist[src] = 0;
priority_queue<pair<double,int>, vector<pair<double,int>>, greater<>> pq;
pq.push({0, src});
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (d > dist[u]) continue;
for (auto &e : adj[u]) {
int v = e.to;
if (v == avoid) continue;
if (dist[v] > dist[u] + e.len) {
dist[v] = dist[u] + e.len;
pre[v] = u;
pq.push({dist[v], v});
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, e;
while (cin >> n >> m >> e) {
for (int i = 1; i <= n; ++i) {
adj[i].clear();
is_exit[i] = false;
}
for (int i = 0; i < m; ++i) {
int a, b, l;
cin >> a >> b >> l;
adj[a].push_back({b, l});
adj[b].push_back({a, l});
}
for (int i = 0; i < e; ++i) {
int x; cin >> x; is_exit[x] = true;
}
int B, P; cin >> B >> P;
dijkstra(P, dist_p); // 警察最短路
dijkstra(B, dist_r, P); // 搶劫犯繞過 P
double ans = INF;
for (int i = 1; i <= n; ++i) if (is_exit[i] && dist_r[i] < INF) {
double need = 0;
for (int u = i; u != -1; u = pre[u]) {
if (dist_p[u] < INF)
need = max(need, 160.0 * dist_r[u] / dist_p[u]);
}
ans = min(ans, need);
}
if (ans == INF) cout << "IMPOSSIBLE\n";
else cout << fixed << setprecision(10) << ans << '\n';
}
return 0;
}
dist_p[u] == INF),該點不構成速度限制double 足夠,輸出 10 位小數保險此題將「雙源最短路 + 路徑重建 + 比率優化」巧妙結合,是圖論綜合應用的優秀範例。