#include<bits/stdc++.h>
#define range(i,a,b) for(int i = (a); i < (b); i++)
#define rep(i,b) for(int i = 0; i < (b); i++)
#define all(a) (a).begin(), (a).end()
#define show(x)  cerr << #x << " = " << (x) << endl;
using namespace std;

const double INF = 1e8;

typedef complex<double> Point;
typedef Point Vector;
//???????????¨????§???????
struct Segment{ Point p1, p2; };
//??´????????¨????§???????
typedef Segment Line;
//????§???¢?????¨????§???????
typedef vector<Point> Polygon;

namespace std{
    bool operator < (const Point &a, const Point &b){
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
    }
    bool operator == (const Point &a, const Point &b){
        return a.real() == b.real() && a.imag() == b.imag();
    }
}

class Circle{
    public:
        Point c;
        double r;
        Circle(Point c = Point(), double r = 0.0): c(c), r(r) {}
};

// ?¨±???????????????
#define EPS (1e-10)

// ????????????a?????¶??????????±???????
//double length = abs(a);

// 2???a,b???????????¢????±???????
//double distance = abs(a-b);

/*
// ????????????a?????????????????????????±???????
Point b = a / abs(a);

// ????????????a?????????????????????n1,n2????±???????
Point n1 = a * Point(0, 1);
Point n2 = a * Point(0, -1);
*/

int ccw(Point, Point, Point);

// 2??????????????????????????????????????????
bool EQ(double a, double b){
    return (abs(a - b) < EPS);
}

// 2??????????????????????????????????????????
bool EQV(Vector a, Vector b){
    return ( EQ(a.real(), b.real()) && EQ(a.imag(), b.imag()) );
}

// ?????? (dot product) : a???b = |a||b|cos??
double dot(Point a, Point b) {
    return (a.real() * b.real() + a.imag() * b.imag());
}

// ?????? (cross product) : a??b = |a||b|sin??
double cross(Point a, Point b) {
    return (a.real() * b.imag() - a.imag() * b.real());
}

// 2??´????????´????????? : a??\b <=> dot(a, b) = 0
bool isOrthogonal(Point a1, Point a2, Point b1, Point b2) {
    return EQ( dot(a1-a2, b1-b2), 0.0 );
}
bool isOrthogonal(Line s1, Line s2) {
    return isOrthogonal(s1.p1, s1.p2, s2.p1, s2.p2);
}

// 2??´?????????????????? : a//b <=> cross(a, b) = 0
bool isParallel(Point a1, Point a2, Point b1, Point b2) {
    return EQ( cross(a1-a2, b1-b2), 0.0 );
}
bool isParallel(Line s1, Line s2) {
    return isParallel(s1.p1, s1.p2, s2.p1, s2.p2);
}

// ???c?????´???a,b????????????????????????
bool isPointOnLine(Point a, Point b, Point c) {
    return EQ( cross(b-a, c-a), 0.0 );
}
bool isPointOnLine(Line s, Point c) {
    return isPointOnLine(s.p1, s.p2, c);
}

// ???a,b???????????´?????¨???c??¨????????¢
double distanceLPoint(Point a, Point b, Point c) {
    return abs(cross(b-a, c-a)) / abs(b-a);
}
double distanceLPoint(Line s, Point c) {
    return distanceLPoint(s.p1, s.p2, c);
}

// ???a,b???????????¨??????????????¨???c??¨????????¢
double distanceLsPoint(Point a, Point b, Point c) {
    if ( dot(b-a, c-a) < EPS ) return abs(c-a);
    if ( dot(a-b, c-b) < EPS ) return abs(c-b);
    return abs(cross(b-a, c-a)) / abs(b-a);
}
double distanceLsPoint(Segment s, Point c) {
    return distanceLsPoint(s.p1, s.p2, c);
}

// a1,a2???????????¨??????????????¨b1,b2???????????¨???????????????????????????
bool isIntersectedLs(Point a1, Point a2, Point b1, Point b2) {
    return ( ccw(a1, a2, b1) * ccw(a1, a2, b2) <= 0 &&
            ccw(b1, b2, a1) * ccw(b1, b2, a2) <= 0 );
}
bool isIntersectedLs(Segment s1, Segment s2) {
    return isIntersectedLs(s1.p1, s1.p2, s2.p1, s2.p2);
}

// a1,a2???????????¨??????????????¨b1,b2???????????¨??????????????????????¨????
Point intersectionLs(Point a1, Point a2, Point b1, Point b2) {
    Vector base = b2 - b1;
    double d1 = abs(cross(base, a1 - b1));
    double d2 = abs(cross(base, a2 - b1));
    double t = d1 / (d1 + d2);

    return Point(a1 + (a2 - a1) * t);
}
Point intersectionLs(Segment s1, Segment s2) {
    return intersectionLs(s1.p1, s1.p2, s2.p1, s2.p2);
}

// a1,a2???????????´?????¨b1,b2???????????´??????????????????
bool isIntersectedL(Point a1, Point a2, Point b1, Point b2) {
    return !EQ( cross(a1-a2, b1-b2), 0.0 );
}
bool isIntersectedL(Line l1, Line l2) {
    return isIntersectedL(l1.p1, l1.p2, l2.p1, l2.p2);
}

// a1,a2???????????´?????¨b1,b2???????????´?????????????¨????
Point intersectionL(Point a1, Point a2, Point b1, Point b2) {
    Point a = a2 - a1; Point b = b2 - b1;
    return a1 + a * cross(b, b1-a1) / cross(b, a);
}
Point intersectionL(Line l1, Line l2) {
    return intersectionL(l1.p1, l1.p2, l2.p1, l2.p2);
}

// ??????s1??¨??????s2????????¢
double distanceLL(Segment s1, Segment s2){
    if(isIntersectedLs(s1.p1, s1.p2, s2.p1, s2.p2) ) return 0.0;
    return min(
            min(distanceLsPoint(s1.p1, s1.p2, s2.p1),
                distanceLsPoint(s1.p1, s1.p2, s2.p2)),
            min(distanceLsPoint(s2.p1, s2.p2, s1.p1),
                distanceLsPoint(s2.p1, s2.p2, s1.p2)) );
}
double distanceLL(Point p0, Point p1, Point p2, Point p3){
    Segment s1 = Segment{p0, p1}, s2 = Segment{p2, p3};
    return distanceLL(s1, s2);
}

// ??????s???????????????p????°???±
Point project(Segment s, Point p){
    Vector base = s.p2 - s.p1;
    double r = dot(p - s.p1, base) / norm(base);
    return Point(s.p1 + base * r);
}

//??????s???????±??????¨?????????p??????????§°??????
Point reflect(Segment s, Point p){
    return Point(p + (project(s, p) - p) * 2.0);
}

//???p???angle?????????????¨???????????????¢
Point rotation(Point p, double angle){
    double x, y;
    x = p.real() * cos(angle) - p.imag() * sin(angle);
    y = p.real() * sin(angle) + p.imag() * cos(angle);
    return Point(x, y);
}

//???c??¨??????l?????????
pair<Point, Point> getCrossPoints(Circle c, Line l){
    Vector pr = project(l, c.c);
    Vector e = (l.p2 - l.p1) / abs(l.p2 - l.p1);
    double base = sqrt(c.r * c.r - norm(pr - c.c));
    return make_pair(pr + e * base, pr - e * base);
}

//???c1??¨???c2?????????
double arg(Vector p) { return atan2(p.imag(), p.real()); }
Vector polar(double a, double r) { return Point(cos(r) * a, sin(r) *a); }

pair<Point, Point> getCrossPoints(Circle c1, Circle c2){
    double d = abs(c1.c - c2.c);
    double a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    double t = arg(c2.c - c1.c);
    return make_pair(Point(c1.c + polar(c1.r, t + a)), Point(c1.c + polar(c1.r, t - a)));
}

//????????????
static const int IN = 2;
static const int ON = 1;
static const int OUT = 0;

int contains(Polygon g, Point p){
    int n = g.size();
    bool x = false;
    rep(i,n){
        Point a = g[i] - p, b = g[(i + 1) % n] - p;
        if( abs(cross(a, b)) < EPS && dot(a,  b) < EPS ) return ON;
        if( a.imag() > b.imag() ) swap(a, b);
        if( a.imag() < EPS && EPS < b.imag() && cross(a, b) > EPS ) x = not x;
    }
    return ( x ? IN : OUT );
}

//???????????????????????????
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

int ccw(Point p0, Point p1, Point p2){
    Vector a = p1 - p0;
    Vector b = p2 - p0;
    if( cross(a, b) > EPS ) return COUNTER_CLOCKWISE;
    if( cross(a, b) < -EPS ) return CLOCKWISE;
    if( dot(a, b) < -EPS ) return ONLINE_BACK;
    if( abs(a) < abs(b) ) return ONLINE_FRONT;

    return ON_SEGMENT;
}

//??????
Polygon convexHull( Polygon s ){
    Polygon u;
    if( s.size() < 3 ) return s;
    sort(s.begin(), s.end());

    range(i,0,s.size()){
        //== COUNTER_CLOCKWISE?????¨????§????180??\???????????´?????????????????§????????????????????¨????????°?????????
        //!= CLOCKWISE?????¨????§????180??????????????´????????????????????°????????????
        for(int n = u.size(); n >= 2 && ccw(u[n-2], u[n-1], s[i]) == COUNTER_CLOCKWISE; n--){
            u.pop_back();
        }
        u.emplace_back(s[i]);
    }

    for(int i = s.size() - 2; i >= 0; i--){
        //????????? == ??¨ != ????????´??????
        for(int n = u.size(); n >= 2 && ccw(u[n-2], u[n-1], s[i]) == COUNTER_CLOCKWISE; n--){
            u.pop_back();
        }
        u.emplace_back(s[i]);
    }

    reverse(u.begin(), u.end());
    u.pop_back();

    //?????????????????????????????§??????????????????????????????????¨??????????????????????
    /*
       int i = 0;
       while(i < u.size() - 1){
       if(u[i].imag() > u[i + 1].imag()){
       u.emplace_back(u[i]);
       u.erase(u.begin());
       continue;
       }else if(u[i].imag() == u[i + 1].imag() && u[i].real() > u[i + 1].real()){
       u.emplace_back(u[i]);
       u.erase(u.begin());
       continue;
       }
       break;
       }
       */

    return u;
}

//?????£?????????????????¨?????????????§???¢?????´???????±???????
double diameterOfConvexPolygon(Polygon p){
    Polygon s = convexHull(p);
    int n = s.size();

    if(n == 2) return abs(s[1] - s[0]);

    int i = 0, j = 0;
    rep(k,n){
        if(not (s[i] < s[k])) i = k;
        if(s[j] < s[k]) j = k;
    }

    double ret = 0.0;
    int is = i, js = j;

    while(i != js || j != is){
        ret = max(ret, abs(s[i] - s[j]));
        if(cross(s[(i + 1) % n] - s[i], s[(j + 1) % n] - s[j]) < 0){
            i = (i + 1) % n;
        }else{
            j = (j + 1) % n;
        }
    }
    return ret;
}

//???????§???¢??????????????????????????¢??°??????????????????????????????????????\????????????
Point getCrossPointLL(Line a, Line b){
    double A = cross(a.p2 - a.p1, b.p2 - b.p1);
    double B = cross(a.p2 - a.p1, a.p2 - b.p1);
    if(abs(A) < EPS && abs(B) < EPS) return b.p1;
    return b.p1 + (b.p2 - b.p1) * (B / A);
}

Polygon convexCut(Polygon p, Line l) {
    Polygon q;
    rep(i,p.size()){
        Point a = p[i], b = p[(i + 1) % p.size()];
        if (ccw(l.p1, l.p2, a) != -1) q.emplace_back(a);
        if (ccw(l.p1, l.p2, a) * ccw(l.p1, l.p2, b) < 0){
            q.emplace_back(getCrossPointLL(Line{a, b}, l));
        }
    }
    return q;
}

//????§???¢?????¢???
double AreaOfTriangle(Point a, Point b, Point c){
    double w, x, y, z;
    w = b.real()-a.real();
    x = b.imag()-a.imag();
    y = c.real()-a.real();
    z = c.imag()-a.imag();
    return abs((w * z - x * y) / 2);
}

//????§???¢?????¢???
double areaOfPolygon(Polygon g){
    int n = g.size();
    double ret = 0.0;
    rep(i,n) ret += cross(g[i], g[ (i + 1) % n ]);
    return abs(ret) / 2.0;
}

//???????§???¢?????????????????????
bool isConvex(Polygon g){
    int n = g.size();
    rep(i,n){
        if(ccw(g[i], g[(i + 1) % n], g[(i + 2) % n]) == CLOCKWISE) return false;
    }
    return true;
}

//???????§???¢?????????l??§??????????????????????§???¢?????°
int dividedPolygonNumber(Polygon p, Line l){
    int cnt = 0;
    rep(i,p.size()){
        if(isIntersectedLs(p[i], p[(i + 1) % p.size()], l.p1, l.p2)) cnt++;
    }
    return cnt / 2 + 1;
}

//????§???¢??????????±???¨??????????????§?¨?
Point pointSymmetry(Polygon g){
    int size = g.size() / 2;
    if(g.size() % 2) return Point{INF,INF};

    set<Point> s;
    rep(i,size){
        rep(j,size){
            if(i == j) continue;
            s.insert(intersectionLs(g[i], g[i + size], g[j], g[j + size]));
        }
    }
    if(s.size() > 1) return Point{INF,INF};
    return *s.begin();
}

class Edge{
    public:
        double to, cost;
        Edge(double to, double cost) : to(to) ,cost(cost) {}
};

class Node{
    public:
        double dis;
        bool isUsed;
        Node(){
            this->dis = INF;
            this->isUsed = 0;
        }
};

typedef vector<vector<Edge>> AdjList;

double dijkstra(AdjList g, int start, int goal, int n){
    vector<Node> node(n);
    priority_queue<double, vector<pair<double, int>>, greater<pair<double, int>>> q;

    q.push(make_pair(0, start));
    node[start].dis = 0;

    pair<double, int> u;
    while(not q.empty()){
        u = q.top(); q.pop();
        int current = u.second;
        node[current].isUsed = 1;

        rep(i,g[current].size()){
            int next = g[current][i].to;
            if(node[next].isUsed == 0){
                if(node[next].dis > node[current].dis + g[current][i].cost){
                    node[next].dis = node[current].dis + g[current][i].cost;
                    q.push(make_pair(node[next].dis, next));
                }
            }
        }
        //rep(i,node.size()){ show(node[i].dis) } cout << endl;
    }

    return node[goal].dis;
}

double distance(vector<Segment> a, vector<Segment> b){
    double mini = INF;
    rep(i,5){
        rep(j,5){
            mini = min(mini,distanceLL(a[i], b[j]));
        }
    }
    return mini;
}

int main(){
    int n, m, l;
    while(cin >> n >> m >> l, n){
        m--; l--;
        vector<Segment> star[105];
        rep(i,n){
            vector<Point> v;
            double x, y, a, r;
            cin >> x >> y >> a >> r;

            Point tmp = rotation(Point(0,r), 2 * M_PI / 360 * a);
            rep(j,5){
                v.emplace_back(Point(tmp.real() + x, tmp.imag() + y));
                tmp = rotation(tmp, 2 * M_PI / 5);
            }
            rep(j,5){
                star[i].emplace_back(Segment{v[j], v[(j + 2) % 5]});
            }
        }
        //rep(i,v.size()){ cout << v[i].x << ' ' << v[i].y << endl; }

        AdjList g(n);
        rep(i,n){
            rep(j,n){
                if(i == j) continue;
                double dis = distance(star[i], star[j]);
                g[i].emplace_back(j,dis);
            }
        }
        cout <<fixed << setprecision(8)<< dijkstra(g,m,l,n) << endl;
    }
}

Measured memory_bytes: 3860