#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const double EPS = 1e-8; static const double PI = 4.0 * atan(1.0); static const double PI2 = 8.0 * atan(1.0); typedef long long ll; typedef unsigned long long ull; #define ALL(c) (c).begin(), (c).end() #define CLEAR(v) memset(v,0,sizeof(v)) #define MP(a,b) make_pair((a),(b)) #define REP(i,n) for(int i=0;i<(int)n;++i) #define ABS(a) ((a)>0?(a):-(a)) template T MIN(const T& a, const T& b) { return a < b ? a : b; } template T MAX(const T& a, const T& b) { return a > b ? a : b; } template void MIN_UPDATE(T& a, const T& b) { if (a > b) a = b; } template void MAX_UPDATE(T& a, const T& b) { if (a < b) a = b; } typedef complex P; double cross(const P& a, const P& b) { return imag(conj(a)*b); } double dot(const P& a, const P& b) { return real(conj(a)*b); } struct L : public vector

{ L() { } L(const P &a, const P &b) { push_back(a); push_back(b); } }; int ccw(P a, P b, P c) { b -= a; c -= a; if (cross(b, c) > 0) return +1; // counter clockwise if (cross(b, c) < 0) return -1; // clockwise if (dot(b, c) < 0) return +2; // c--a--b on line if (norm(b) < norm(c)) return -2; // a--b--c on line return 0; } bool intersectSS(const L &s, const L &t) { return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0; } bool intersectSP(const L &s, const P &p) { return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS; // triangle inequality } P projection(const L &l, const P &p) { double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]); return l[0] + t*(l[0]-l[1]); } double distanceSP(const L &s, const P &p) { const P r = projection(s, p); if (intersectSP(s, r)) return abs(r - p); return min(abs(s[0] - p), abs(s[1] - p)); } double distanceSS(const L &s, const L &t) { if (intersectSS(s, t)) return 0; return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])), min(distanceSP(t, s[0]), distanceSP(t, s[1]))); } struct Star { L s[5]; Star(double x, double y, double a, double r) { REP(i, 5) { double a0 = a * PI2 / 360.0 + i * PI2 / 5.0 + PI / 2.0; double a1 = a * PI2 / 360.0 + (i + 2) * PI2 / 5.0 + PI / 2.0; s[i] = L(polar(r, a0) + P(x, y), polar(r, a1) + P(x, y)); } } double distance(const Star& rh) const { double minValue = 1e10; REP(i, 5) REP(j, 5) { MIN_UPDATE(minValue, distanceSS(s[i], rh.s[j])); } return minValue; } }; int main() { std::ios::sync_with_stdio(false); int N, M, L; while (cin >> N >> M >> L && (N || M || L)) { --M; --L; vector stars; REP(n, N) { double x, y, a, r; cin >> x >> y >> a >> r; stars.push_back(Star(x, y, a, r)); } vector dp(N, 1e10); dp[M] = 0.0; multiset > open; open.insert(MP(0.0, M)); while (!open.empty()) { double currentCost = open.begin()->first; int currentNode = open.begin()->second; open.erase(open.begin()); if (dp[currentNode] != currentCost) { continue; } REP(to, N) { double cost = currentCost + stars[currentNode].distance(stars[to]); if (dp[to] > cost) { open.insert(MP(dp[to] = cost, to)); } } } printf("%.20f\n", dp[L]); } }