L1 到 L2 之间连边权值 |C1−C2| / √ A2+B2
线 L 与圆 i 之间连边权值 max(0, d(Oi , L1) − ri)
圆 i 与圆 j 之间连边权值 max(0, d(Oi , Oj ) − ri − rj )
求 L1 到 L2 的最短路即可。
#include<bits/stdc++.h>
#define ios1 ios::sync_with_stdio(0)
#define ios2 cin.tie(0)
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 5000;
int n, A, B, C1, C2;
double Map[maxn][maxn];
struct node{
double x, y, r;
}circle[maxn];
void init() {
for(int i = 0 ; i <= n + 1; i++){
for(int j = 0; j <= n + 1; j++) {
if(i == j)Map[i][j] = 0;
else Map[i][j] = inf;
}
}
}
bool cmp (node p, node q) {
if(p.x == q.x)return p.y < p.y;
return p.x < p.y;
}
double dis[maxn];
bool vis[maxn];
void Dijkstra() {
for (int i = 0; i <= n+1; i++) {
dis[i] = Map[0][i];
}
vis[0] = 1;
for (int i = 0; i < n+1; i++) {
double MIN = inf;
int x = -1;
for (int j = 0; j <= n+1; j++) {
if (!vis[j] && dis[j]<MIN) {
MIN = dis[j];
x = j;
}
}
vis[x] = 1;
for (int j = 0; j <= n+1; j++) {
if (!vis[j] && MIN + Map[x][j]<dis[j]) {
dis[j] = Map[x][j] + MIN;
}
}
}
}
int main() {
ios1; ios2;
while(cin >> n >> A >> B >> C1 >> C2) {
for(int i = 1; i <= n; i++) {
cin >> circle[i].x >> circle[i].y >> circle[i].r;
}
init();
Map[0][n+1] = Map[n+1][0] = abs(C1-C2)/sqrt(A*A+B*B);
for(int i = 1; i <= n; i++) {
double k = abs(A*circle[i].x + B*circle[i].y + C1)/sqrt(A*A+B*B) - circle[i].r;
if(k < 0)k = 0;
Map[0][i] = Map[i][0] = k;
}
for(int i = 1; i <= n; i++) {
double k = abs(A*circle[i].x + B*circle[i].y + C2)/sqrt(A*A+B*B) - circle[i].r;
if(k < 0)k = 0;
Map[i][n+1] = Map[n+1][i] = k;
}
for(int i = 1 ; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i != j){
double k = sqrt(abs(circle[i].x - circle[j].x) * abs(circle[i].x - circle[j].x) + abs(circle[i].y - circle[j].y) * abs(circle[i].y - circle[j].y)) - circle[i].r - circle[j].r;
if(k < 0)k = 0;
Map[i][j] = k;
}
}
}
memset(vis, 0, sizeof(vis));
Dijkstra();
printf("%lf\n", dis[n+1]);
}
return 0;
}