测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A17496. 能量护盾

填空题 困难

题目描述

能量护盾

题目描述

在一处被宇宙射线笼罩的星域中,你驾驶着一艘小型探索飞船,需要从坐标 (xs,ys) 航行到坐标 (xt,yt)。

飞船可以以速度 1 向任意方向移动,自身视为一个点。

星域中分布着 N 个圆形能量护盾,第 i 个护盾的圆心为 (xi,yi),半径为 ri。护盾之间可能相互重叠,也可能存在包含关系。

飞船一旦进入某个护盾的内部,就能免受宇宙射线的伤害。若一个点不在任何护盾内部,则飞船会持续受到宇宙射线的照射。

你的目标是:在从起点到终点的航行过程中,尽可能减少受到宇宙射线照射的总时间。

请你计算这个最小照射时间。

输入格式

第一行,四个整数 xs,ys,xt,yt,分别表示起点和终点的坐标。

第二行,一个整数 N,表示圆形护盾的数量。

接下来 N 行,每行三个整数 xi,yi,ri,描述第 i 个护盾的圆心坐标和半径。

输出格式

输出一个实数,表示受到宇宙射线照射的最小时间,保留 10 位小数。

输入样例#1

-2 -2 2 2
1
0 0 1

输出样例#1

3.6568542495

输入样例#2

-2 0 2 0
2
-1 0 2
1 0 2

输出样例#2

0.0000000000

输入样例#3

4 -2 -2 4
3
0 0 2
4 0 1
0 4 1

输出样例#3

4.0000000000

说明提示

−109≤xs,ys,xt,yt≤109

(xs,ys)≠(xt,yt)

1≤N≤1000

−109≤xi,yi≤109

1≤ri≤109

参考答案

#include <iostream> #include <vector> #include <cmath> #include <iomanip> #include <algorithm> using namespace std; typedef long long ll; const double INF = 1e18; const double eps = 1e-8; struct Point { ll x, y; Point() {} Point(ll x_, ll y_) : x(x_), y(y_) {} }; struct Circle { ll x, y, r; Circle() {} Circle(ll x_, ll y_, ll r_) : x(x_), y(y_), r(r_) {} }; // 两点距离 double dis_pp(const Point& a, const Point& b) { ll dx = a.x - b.x; ll dy = a.y - b.y; return sqrt(1.0 * dx * dx + 1.0 * dy * dy); } // 点到圆的暴露长度,点在圆内返回0 double dis_pc(const Point& p, const Circle& c) { double d = dis_pp(p, Point(c.x, c.y)); if (d <= c.r + eps) return 0.0; return d - c.r; } // 两个圆之间暴露长度,相交/包含返回0 double dis_cc(const Circle& a, const Circle& b) { double d = dis_pp(Point(a.x, a.y), Point(b.x, b.y)); double sumr = a.r + b.r; if (d <= sumr + eps) return 0.0; return d - sumr; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout << fixed << setprecision(10); ll xs, ys, xt, yt; cin >> xs >> ys >> xt >> yt; Point S(xs, ys), T(xt, yt); int N; cin >> N; vector<Circle> cir(N); for (int i = 0; i < N; i++) { cin >> cir[i].x >> cir[i].y >> cir[i].r; } // 总点数:0起点,1~N护盾,N+1终点 int tot = N + 2; vector<vector<double>> g(tot, vector<double>(tot, INF)); for (int i = 0; i < tot; i++) g[i][i] = 0; // 0(S) <-> N+1(T) g[0][N+1] = dis_pp(S, T); g[N+1][0] = dis_pp(S, T); // 0(S) 和所有护盾 1~N for (int i = 1; i <= N; i++) { double d = dis_pc(S, cir[i-1]); g[0][i] = d; g[i][0] = d; } // N+1(T) 和所有护盾 1~N for (int i = 1; i <= N; i++) { double d = dis_pc(T, cir[i-1]); g[N+1][i] = d; g[i][N+1] = d; } // 护盾之间 i,j (1~N) for (int i = 1; i <= N; i++) { for (int j = i + 1; j <= N; j++) { double d = dis_cc(cir[i-1], cir[j-1]); g[i][j] = d; g[j][i] = d; } } // Floyd 求全源最短路,N<=1000 tot=1002,1e9?不行!换Dijkstra单源 vector<double> dist(tot, INF); vector<bool> vis(tot, false); dist[0] = 0; for (int step = 0; step < tot; step++) { int u = -1; double minv = INF; for (int i = 0; i < tot; i++) { if (!vis[i] && dist[i] < minv) { minv = dist[i]; u = i; } } if (u == -1) break; vis[u] = true; for (int v = 0; v < tot; v++) { if (g[u][v] < INF && dist[v] > dist[u] + g[u][v]) { dist[v] = dist[u] + g[u][v]; } } } cout << dist[N+1] << endl; return 0; }
上一题 下一题