/*
    author : aryan57
    created : 06-June-2021 18:04:35 IST
*/
#include <bits/stdc++.h>
using namespace std;

template <typename A, typename B>
ostream &operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')'; }
template <typename T_container, typename T = typename enable_if<!is_same<T_container, string>::value, typename T_container::value_type>::type>
ostream &operator<<(ostream &os, const T_container &v)
{
    os << '{';
    string sep;
    for (const T &x : v)
        os << sep << x, sep = ", ";
    return os << '}';
}
void dbg_out() { cerr << endl; }
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T)
{
    cerr << ' ' << H;
    dbg_out(T...);
}
#ifndef ONLINE_JUDGE
#define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#else
#define dbg(...)
#endif

#define int long long
#define X first
#define Y second
#define pb push_back
#define sz(a) ((int)(a).size())
#define all(a) (a).begin(), (a).end()
#define F(i, a, b) for (int i = a; i <= b; i++)
#define RF(i, a, b) for (int i = a; i >= b; i--)

const int mxn = 1e5;
const long long INF = 1e16;
const int32_t M = 1000000007;
// const int32_t M = 998244353;
const long double pie = acos(-1);

struct Edge
{
    int u, v, d, c;
};


void solve_LOG()
{
    int n, m;
    cin >> n >> m;

    vector<Edge> adj[n + 1];

    F(i, 1, m)
    {
        Edge e;
        cin >> e.u >> e.v >> e.c >> e.d;
        // if(e.u==e.v)continue;
        adj[e.u].push_back(e);
        adj[e.v].push_back(e);
    }

    vector<int> mn(n + 1, INF);

    mn[1] = 0;

    using pii = pair<int, int>;
    priority_queue<pii, vector<pii>, greater<pii>> q;
    q.push({0, 1});
    while (!q.empty())
    {
        int v = q.top().second;
        int mn_v = q.top().first;
        q.pop();
        if (mn_v != mn[v])
            continue;

        for (auto edge : adj[v])
        {
            int c=edge.c;
            int d=edge.d;

            int to=-1;
            if(edge.u==v)to=edge.v;
            else to=edge.u;

            int temp=INF;

            int dd=(int)sqrt(d);

            F(t,max(0ll,dd-(mn[v]+1)-5),max(0ll,dd-(mn[v]+1)+5))
            {
                temp=min(temp,mn[v]+t+c+d/(mn[v]+t+1));
            }

            if (temp < mn[to])
            {
                mn[to] = temp;
                q.push({mn[to], to});
            }
        }
    }

    if (mn[n] == INF)
    {
        cout << "-1\n";
        return;
    }

    cout << mn[n];
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
#ifdef ARYAN_SIEVE
    sieve();
#endif
#ifdef ARYAN_SEG_SIEVE
    segmented_sieve();
#endif
#ifdef ARYAN_FACT
    fact_init();
#endif
    // cout<<fixed<<setprecision(10);
    int _t = 1;
    // cin>>_t;
    for (int i = 1; i <= _t; i++)
    {
        // cout<<"Case #"<<i<<": ";
        solve_LOG();
    }
    return 0;
}
//	parsed : 06-June-2021 18:04:32 IST
// abc181_f
#include <bits/stdc++.h>
#ifdef LOCAL
#include "../cxx-prettyprint/prettyprint.hpp"
#endif
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

#define REP(i, n) for (int (i) = 0 ; (i) < (int)(n) ; ++(i))
#define REPN(i, m, n) for (int (i) = m ; (i) < (int)(n) ; ++(i))
#define REP_REV(i, n) for (int (i) = (int)(n) - 1 ; (i) >= 0 ; --(i))
#define REPN_REV(i, m, n) for (int (i) = (int)(n) - 1 ; (i) >= m ; --(i))
#define ALL(x) x.begin(), x.end()

#define INF (ll)(1e9)
#define MOD (1000000007)

#define print2D(h, w, arr) REP(i, h) { REP(j, w) cout << arr[i][j] << " "; cout << endl; }
#define print_line(vec, n) {for(int idx=0;idx<(n-1);idx++) cout << (vec)[idx] << " "; cout << (vec)[(n)-1] << endl;}
template<class T> void print(const T& x){cout << x << "\n";}
template<class T, class... A> void print(const T& first, const A&... rest) { cout << first << " "; print(rest...); }
struct PreMain {PreMain(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(20);}} premain;

struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<int> rank;
    vector<int> size; // size[i]: iが親なら連結成分の数

    UnionFind(int N) : par(N), rank(N), size(N) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) {par[i] = i; rank[i] = 0; size[i] = 1;}
    }

    int find(int x) { // データxが属する木の根を再帰で得る：find(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }

    void unite(int x, int y) { // xとyの木を併合
        int rx = find(x); //xの根をrx
        int ry = find(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま

        // rank[rx] >= rank[ry] となるように rx と ry を swap
        if(rank[rx] < rank[ry]) swap(rx, ry);

        // 同じ高さだったならばまとめたことによって高さ +1
        if(rank[rx] == rank[ry]) ++rank[rx];

        par[ry] = rx; // root rx に ry の木をつなぐ
        size[rx] += size[ry];
        size[ry] = 0;

    }

    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = find(x);
        int ry = find(y);
        return rx == ry;
    }

    int get_size(int x){
        int rx = find(x);
        return size[rx];
    }
};

int N;
vector<vector<double>> dist;

bool valid(double r){

    UnionFind uf(N+2);
    REP(i, N+2) REPN(j, i+1, N+2){
        if (dist[i][j] < 2 * r){
            uf.unite(i, j);
        }
    }
    return not uf.same(N, N+1);
}

int main() {
#ifdef LOCAL
    ifstream in("../arg.txt"); cin.rdbuf(in.rdbuf());
#endif

    cin >> N;

    vector<P> points(N);
    REP(i, N) cin >> points[i].first >> points[i].second;

    dist.assign(N+2, vector<double>(N+2));
    REP(i, N) {
        REP(j, N){
            dist[i][j] = sqrt((points[i].first - points[j].first) * (points[i].first - points[j].first) + (points[i].second - points[j].second) * (points[i].second - points[j].second));
        }
        dist[i][N] = 100 - points[i].second;
        dist[i][N+1] = points[i].second + 100;
    }
    REP(j, N){
        dist[N][j] = 100 - points[j].second;
        dist[N+1][j] = points[j].second + 100;
    }
    dist[N][N] = 0;
    dist[N+1][N+1] = 0;
    dist[N][N+1] = 200;
    dist[N+1][N] = 200;

    double ok = 0;
    double ng = 101;
    while (ng - ok > 1e-8){
        double mid = (ok + ng) / 2;
        if (valid(mid)){
            ok = mid;
        } else {
            ng = mid;
        }
    }

    print(ok);

    return 0;
}
