import std.stdio;
import std.ascii;
import std.range;
import std.array;
import std.functional;
import std.algorithm;
import std.conv;
import std.container;
import std.math;
import std.numeric;
import std.string;
import std.c.string;
import std.random;
import std.regex;
import std.typecons;

const EPS = 1e-8;

struct Point {
    double x, y;
    Point opBinary(alias op)(in Point p) const {
        static if (op == "+") {
            return Point(x + p.x, y + p.y);
        } else if (op == "-") {
            return Point(x - p.x, y - p.y);
        }
    }
    Point opBinary(alias op)(double k) const {
        static if (op == "*") {
            return Point(x * k, y * k);
        }
    }
}
double norm(in Point p) {
    return sqrt(p.x * p.x + p.y * p.y);
}

double dot(in Point a, in Point b) {
    return a.x * b.x + a.y * b.y;
}

double cross(in Point a, in Point b) {
    return a.x * b.y - a.y * b.x;
}

int ccw(Point a, Point b, Point c){
    b = b - a; c = c - a;
    if (cross(b, c) > EPS) return +1; 
    if (cross(b, c) < -EPS) return -1;
    if (dot(b, c) < 0) return +2;     
    if (b.norm < c.norm) return -2;  
    return 0;                       
}

struct Segment {
    Point a, b;
}
bool contains(in Segment s, in Point p) {
    Point u = s.a - p,
          v = s.b - p;
    return abs(cross(u, v)) < EPS && dot(u, v) < -EPS;
}

double distance(in Point a, in Point b) {
    double dx = a.x - b.x,
           dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

Point projection(in Segment s, in Point p) {
    Point u = s.b - s.a,
          v = p - s.a;
    double n = u.norm;
    return s.a + u * (dot(u, v) / (n * n));
}

double distance(in Segment s, in Point p) {
    auto ret = min(distance(p, s.a), distance(p, s.b));
    Point proj = s.projection(p);
    if (s.contains(proj)) {
        ret = min(ret, (p - proj).norm);
    }
    return ret;
}
double distance(in Point p, in Segment s) {
    return distance(s, p);
}

bool intersect(in Segment s, in Segment t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

double distance(in Segment s, in Segment t) {
    if (intersect(s, t)) return 0;
    return min( distance(s.a, t), distance(s.b, t),
                distance(s, t.a), distance(s, t.b) );
}

void main() {

    int N, M, L;
    Segment[][] S;
    
    bool input() {
        scanf("%d %d %d\n", &N, &M, &L);
        if (N == 0 && M == 0 && L == 0) return false;
        S = new Segment[][N];
        foreach (i; 0 .. N) {
            double x, y, a, r;
            scanf("%lf %lf %lf %lf\n", &x, &y, &a, &r);
            auto Ps = new Point[5];
            double d = 2.0 * PI / 5.0;
            a = 2.0 * PI / 360 * a;
            foreach (j; 0 .. 5) {
                Ps[j] = Point(x - r * sin(a + d * j), y + r * cos(a + d * j));
            }
            S[i] = new Segment[5];
            foreach (j; 0 .. 5) {
                S[i][j] = Segment(Ps[j], Ps[(j + 2) % 5]);
            }
        }
        return true;
    }

    void solve() {
        auto G = new double[][](N, N);
        foreach (i; 0 .. N) G[i][] = 1e9;
        M--; L--;
        foreach (i; 0 .. N) {
            foreach (j; 0 .. N) {
                foreach (a; 0 .. 5) {
                    foreach (b; 0 .. 5) {
                        G[i][j] = min(G[i][j], distance(S[i][a], S[j][b]));
                    }
                }
            }
        }
        foreach (k; 0 .. N) {
            foreach (i; 0 .. N) {
                foreach (j; 0 .. N) {
                    G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
                }
            }
        }
        writefln("%.10f", G[M][L]);
    }

    while (input) solve;
}

Measured memory_bytes: 2032