// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

using lint = long long int;

using pint = pair<int, int>;

using plint = pair<lint, lint>;

struct fast_ios { fast_ios(){ cin.tie(0); ios::sync_with_stdio(false); cout << fixed << setprecision(20); }; } fast_ios_;

#define ALL(x) (x).begin(), (x).end()

#define SZ(x) ((lint)(x).size())

#define POW2(n) (1LL << (n))

#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)

#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)

#define REP(i, n) FOR(i,0,n)

#define IREP(i, n) IFOR(i,0,n)

template<typename T> istream &operator>>(istream &is, vector<T> &vec){ for (auto &v : vec) is >> v; return is; }

template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec){ os << "["; for (auto v : vec) os << v << ","; os << "]"; return os; }

template<typename T> ostream &operator<<(ostream &os, const deque<T> &vec){ os << "deq["; for (auto v : vec) os << v << ","; os << "]"; return os; }

template<typename T> ostream &operator<<(ostream &os, const set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }

template<typename T> ostream &operator<<(ostream &os, const unordered_set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }

template<typename T> ostream &operator<<(ostream &os, const multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }

template<typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }

template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa){ os << "(" << pa.first << "," << pa.second << ")"; return os; }

template<typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }

template<typename TK, typename TV> ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }

template<typename T> void ndarray(vector<T> &vec, int len) { vec.resize(len); }

template<typename T, typename... Args> void ndarray(vector<T> &vec, int len, Args... args) { vec.resize(len); for (auto &v : vec) ndarray(v, args...); }

template<typename T> bool mmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; }

template<typename T> bool mmin(T &m, const T q) { if (q < m) {m = q; return true;} else return false; }

template<typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }

template<typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }

#define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl;

/*

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>

#include <ext/pb_ds/tag_and_trait.hpp>

using namespace __gnu_pbds; // find_by_order(), order_of_key()

template<typename TK> using pbds_set = tree<TK, null_type, less<TK>, rb_tree_tag, tree_order_statistics_node_update>;

template<typename TK, typename TV> using pbds_map = tree<TK, TV, less<TK>, rb_tree_tag, tree_order_statistics_node_update>;

*/



using T_P = double;

constexpr T_P EPS = 1E-8;

struct P

{

    T_P x, y;

    P(T_P x = 0, T_P y = 0) : x(x), y(y) {}

    P(pair<T_P, T_P> p) : x(p.first), y(p.second) {}

    static T_P add_w_error(T_P a, T_P b) { return (abs(a + b) < EPS * (abs(a) + abs(b))) ? 0 : a + b; }

    P operator+(const P &p) const { return P(add_w_error(x, p.x), add_w_error(y, p.y)); }

    P operator-(const P &p) const { return P(add_w_error(x, -p.x), add_w_error(y, -p.y)); }

    P operator*(const P &p) const { return P(add_w_error(x * p.x,  -y * p.y), add_w_error(x * p.y, y * p.x)); }

    P operator*(T_P d) const { return P(x * d, y * d); }

    P operator/(T_P d) const { return P(x / d, y / d); }

    P inv() const { return conj() / norm2(); }

    P operator/(const P &p) const { return (*this) * p.inv(); }

    bool operator<(const P &r) const{ return x != r.x ? x < r.x : y < r.y; }

    bool operator==(const P &r) const{ return add_w_error(x, -r.x) == 0 and add_w_error(y, -r.y) == 0; }

    T_P dot(P p) const { return add_w_error(x * p.x, y * p.y); }

    T_P det(P p) const { return add_w_error(x * p.y, -y * p.x); }

    T_P norm() const { return sqrt(x * x + y * y); }

    T_P norm2() const { return x * x + y * y; }

    T_P arg() const { return atan2(y, x); }

    // rotate point/vector by rad

    P rotate(T_P rad) { return P(add_w_error(x * cos(rad), -y * sin(rad)), add_w_error(x * sin(rad), y * cos(rad))); }

    P conj() const { return P(x, -y); }

    friend istream &operator>>(istream &is, P &p) { T_P x, y; is >> x >> y; p = P(x, y); return is; }

    friend ostream &operator<<(ostream &os, const P &p) { os << '(' << p.x << ',' << p.y << ')'; return os; }

};



vector<P> sol(P a, P b, double Ra, double Rb) {

    double d = (a - b).norm();

    double rc = (d * d + Ra * Ra - Rb * Rb) / (2 * d);

    double rs = sqrt(Ra * Ra - rc * rc);

    P diff = (b - a) / d;

    return {a + diff * P(rc, rs), a + diff * P(rc, -rs)};

}



int main()

{

    int N, K;

    cin >> N >> K;

    double lo = 0.0, hi = 1.0e9;

    vector<double> X(N), Y(N), C(N);

    vector<P> Center(N);

    REP(i, N) cin >> X[i] >> Y[i] >> C[i];

    REP(i, N) Center[i] = P(X[i], Y[i]);

    REP(d, 100)

    {

        double t = (lo + hi) / 2;

        vector<double> R(N);

        REP(i, N) R[i] = t / C[i];

        int maxi = 0;

        REP(i, N) REP(j, N) {

            vector<P> vp{Center[i]};

            if (i != j and (Center[i] - Center[j]).norm() < R[i] + R[j]) {

                vp = sol(Center[i], Center[j], R[i], R[j]);

            }

            for (auto p : vp)

            {

                int cnt = 0;

                REP(i, N) if ((Center[i] - p).norm() <= R[i] + EPS) cnt++;

                mmax(maxi, cnt);

            }

        }

        (maxi >= K ? hi : lo) = t;

    }

    cout << lo << endl;

}

// Optimized solution to the same problem (faster):
#define _CRT_SECURE_NO_WARNINGS

#include <bits/stdc++.h>

#include <random>

using namespace std;

#define rep(i,a,n) for (int i=a;i<n;i++)

#define per(i,a,n) for (int i=n-1;i>=a;i--)

#define pb push_back

#define mp make_pair

#define all(x) (x).begin(),(x).end()

#define fi first

#define se second

#define sz(x) ((int)(x).size())

typedef vector<int> vi;

typedef long long ll;

typedef pair<int, int> pii;

typedef double db;

mt19937 mrand(random_device{}());

const ll mod = 1000000007;

int rnd(int x) { return mrand() % x; }

ll powmod(ll a, ll b) { ll res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1)res = res * a%mod; a = a * a%mod; }return res; }

ll gcd(ll a, ll b) { return b ? gcd(b, a%b) : a; }

// head



//#define RG

const long double eps = 1e-8;

typedef long double ld;

int t;

struct Point {

    Point() {}

    Point(ld xx, ld yy): x(xx),y(yy) {}

    long double x,y;

}pts[100];

int c[100];



ld getDis(Point& a, Point& b) {

    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}



Point calPointInDirAndDis(Point from, ld dis, Point to) {

    Point ans;

    if(abs(getDis(from,to)) <eps) return from;

    ld _ratio = dis/getDis(from,to);

    ans.x = from.x + _ratio*(to.x-from.x);

    ans.y = from.y + _ratio*(to.y-from.y);

    return ans;

}



vector<Point> getCrossPoint(long double T, int i, int j) {

    ld ri = T/c[i];

    ld rj = T/c[j];

    ld dd = getDis(pts[i],pts[j]);

    //cout<<"ririri:"<<ri<<endl;

    //cout<<"rjrjrj:"<<rj<<endl;

    //没有交点，且大的圆包含小的圆，返回大的圆的圆心

    if(abs(ri-rj)>dd && abs(abs(ri-rj)-dd) > eps) {

        vector<Point> ans;

        ans.push_back(pts[i]);

        ans.push_back(pts[j]);

        return ans;

    }

    //没有交点，两个圆无包含关系

    if(abs(ri+rj)<dd && abs(ri+rj-dd) > eps) {

        return vector<Point>{pts[i],pts[j]};

    }

    ld ao = (ri*ri-rj*rj+dd*dd)/(2.0*dd);

    Point o = calPointInDirAndDis(pts[i], ao, pts[j]);

    ld co=0.0;

    //cout<<"aoaoao:"<<ao<<endl;

    //if(ri*ri-ao*ao < 0 || abs(ri*ri-ao*ao) < eps)

    if(ri*ri-ao*ao < 0 )

        return vector<Point>{pts[i],pts[j]};

    co = sqrt(ri*ri-ao*ao);

    Point c,d;

    c.x = o.x + (pts[j].y-pts[i].y);

    c.y = o.y - (pts[j].x-pts[i].x);

    d.x = o.x - (pts[j].y-pts[i].y);

    d.y = o.y + (pts[j].x-pts[i].x);

    //cout<<"OOOOOO:"<<o.x<<","<<o.y<<endl;

    //cout<<"cococo:"<<co<<endl;

    c = calPointInDirAndDis(o, co, c);

    d = calPointInDirAndDis(o, co, d);

    vector<Point> ans;

    ans.push_back(c);

    ans.push_back(d);

    return ans;

}

Point operator*(const Point& a, const Point &p) { return Point(a.x * p.x + (-a.y * p.y), (a.x * p.y +  a.y * p.x)); }

Point operator+(const Point& a, const Point &p) { return Point(a.x + p.x , a.y + p.y); }

vector<Point> getCrossPoint2(Point a, Point b, double Ra, double Rb) {

    //double d = (a - b).norm();

    double d = getDis(a,b);

    double rc = (d * d + Ra * Ra - Rb * Rb) / (2 * d);

    double rs = sqrt(Ra * Ra - rc * rc);

    Point diff;

    diff.x  = (b.x - a.x) / d;

    diff.y  = (b.y - a.y) / d;

    //return {a + diff * Point(rc, rs), a + diff * Point(rc, -rs)};

    vector<Point> ans;

    return {a + diff * Point(rc, rs), a + diff * Point(rc, -rs)};

}

int disLessTciNum(Point p, int n, ld T) {

    int cnt = 0;

    for(int i=0;i<n;++i) {

        //if(getDis(p, pts[i])<=T/c[i] || abs(getDis(p, pts[i])-T/c[i]) < eps) cnt++;

        if(getDis(p, pts[i])<=(T/c[i]+eps)) cnt++;

    }

    //cout<<"cnt::"<<cnt<<endl;

    return cnt;

}



Point anspt;

bool getCount(long double T,int n, int k) {

    rep(i,0,n) {

        rep(j,0,n) {

            //vector<Point> crossPts{pts[i]};

            vector<Point> crossPts;

            if(i!=j) {

                crossPts = getCrossPoint(T, i, j);

                //vector<Point> crossPts = getCrossPoint2(pts[i], pts[j], T/c[i], T/c[j]);

                //cout<<"crossPts0:"<<crossPts[0].x<<","<<crossPts[0].y<<endl;

                //cout<<"crossPts1:"<<crossPts[1].x<<","<<crossPts[1].y<<endl;

            }

            if(crossPts.size()==0) continue;

            if(disLessTciNum(crossPts[0],n,T) >= k) {

                anspt = crossPts[0];

                return true;

            }

            if(disLessTciNum(crossPts[1],n,T) >= k) {

                anspt = crossPts[1];

                return true;

            }

        }

    }

    return false;

}



int main()

{

    ios::sync_with_stdio(false);

#ifdef RG

    freopen("input.txt", "r", stdin);

    freopen("output.txt", "w", stdout); 

#endif

    int n,k;

    cin>>n>>k;

    rep(i,0,n) {

        cin>>pts[i].x>>pts[i].y;

        cin>>c[i];

    }

    if(k==1) cout<<0<<endl;

    else {

        long double lt = 0.0,rt = 4000.0*100;

        while(abs(rt-lt) > eps) {

            long double mt = (lt+rt)/2;

            //cout<<"mt:::"<<mt<<endl;

            if(getCount(mt,n,k) ) {

                rt = mt;

            } else {

                lt = mt;

            }

        }

        //cout<<lt<<endl;

        printf("%.20Lf\n", lt);

    }

    return 0;

}

// Fastest known solution for this problem: