Problem:
Score : 600 points

Problem Statement

Takahashi wants to grill N pieces of meat on a grilling net, which can be seen as a two-dimensional plane. The coordinates of the i-th piece of meat are \left(x_i, y_i\right), and its hardness is c_i.

Takahashi can use one heat source to grill the meat. If he puts the heat source at coordinates \left(X, Y\right), where X and Y are real numbers, the i-th piece of meat will be ready to eat in c_i \times \sqrt{\left(X - x_i\right)^2 + \left(Y-y_i\right)^2} seconds.

Takahashi wants to eat K pieces of meat. Find the time required to have K or more pieces of meat ready if he put the heat source to minimize this time.

Constraints

All values in input are integers.

1 \leq N \leq 60

1 \leq K \leq N

-1000 \leq x_i , y_i \leq 1000

\left(x_i, y_i\right) \neq \left(x_j, y_j\right) \left(i \neq j \right)

1 \leq c_i \leq 100

Input

Input is given from Standard Input in the following format:

N K
x_1 y_1 c_1
\vdots
x_N y_N c_N

Output

Print the answer.

It will be considered correct if its absolute or relative error from our answer is at most 10^{-6}.

Sample Input 1

4 3
-1 0 3
0 0 3
1 0 2
1 1 40

Sample Output 1

2.4

If we put the heat source at \left(-0.2, 0\right), the 1-st, 2-nd, and 3-rd pieces of meat will be ready to eat within 2.4 seconds. This is the optimal place to put the heat source.

Sample Input 2

10 5
-879 981 26
890 -406 81
512 859 97
362 -955 25
128 553 17
-885 763 2
449 310 57
-656 -204 11
-270 76 40
184 170 16

Sample Output 2

7411.2252

Solution in C++14 (Clang 3.8.0) (judge verdict: Wrong Answer)

#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <climits>
#include <cstring>
#include <cassert>

#define rep(i, m, n) for(int i=int(m);i<int(n);i++)
#define all(c) begin(c),end(c)

template<typename T1, typename T2>
inline void chmin(T1 &a, T2 b) { if (a > b) a = b; }

template<typename T1, typename T2>
inline void chmax(T1 &a, T2 b) { if (a < b) a = b; }

typedef long long int ll;
using ll = long long int;
using ull = long long unsigned int;
using Int = long long int;
using namespace std;
#define INF (1 << 30) - 1
#define INFl (ll)5e15
#define DEBUG 0
#define dump(x)  cerr << #x << " = " << (x) << endl
#define MOD 1000000007


//edit
namespace Geometory {
    const double EPS = 1e-10;

    inline bool equals(double a, double b) {
        return fabs(a - b) < EPS;
    }

    struct Point {
        double x, y;

        Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

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

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

        Point operator*(const double k) {
            return Point(x * k, y * k);
        }

        Point operator/(const double k) {
            return Point(x / k, y / k);
        }

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

        double abs() const {
            return sqrt(norm());
        }

        double dot(Point p) {
            return x * p.x + y * p.y;
        }

        double cross(Point p) {
            return x * p.y - y * p.x;
        }

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

        bool operator==(const Point &p) const {
            return equals(x, p.x) && equals(y, p.y);
//            return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
        }


    };

    using Vector = Point;

    struct Segment {
        Point p1, p2;

        Segment() {}

        Segment(Point p1, Point p2) : p1(p1), p2(p2) {}

        Segment(double x1, double y1, double x2, double y2) : p1(x1, y1), p2(x2, y2) {}
    };

    using Line = Segment;


    double norm(Vector p) {
        return p.x * p.x + p.y * p.y;
    }

    double abs(Vector a) {
        return sqrt(norm(a));
    }

    double dot(Vector a, Vector b) {
        return a.dot(b);
    }

    double cross(Vector a, Vector b) {
        return a.cross(b);
    }

    //直行判定
    bool is_orthogonal(Vector a, Vector b) {
        return equals(dot(a, b), 0.0);
    }

    bool is_orthogonal(Point a1, Point a2, Point b1, Point b2) {
        return is_orthogonal(a1 - a2, b1 - b2);
    }

    bool is_orthogonal(Segment s1, Segment s2) {
        return equals(dot(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
    }

    //平行判定
    bool is_parallel(Vector a, Vector b) {
        return equals(cross(a, b), 0.0);
    }

    bool is_parallel(Point a1, Point a2, Point b1, Point b2) {
        return is_parallel(a1 - a2, b1 - b2);
    }

    bool is_parallel(Segment s1, Segment s2) {
        return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
    }

    //反時計回り
    static const int CCW = 1; // Counter Clockwise
    static const int CW = -1; // Clockwise
    static const int OB = 2; // Online Back
    static const int OF = -2; // Online Front
    static const int OS = 0; // On Segment

    // p0を中心としたとき、p2は{反時計回り、時計回り、p2->p0->p1で同一直線上、p0->p1->p2で直線上、p2がp0p1線分上} (後ろの3つの説明は雑)
    int ccw(Point p0, Point p1, Point p2) {
        Vector a = p1 - p0;
        Vector b = p2 - p0;
        if (cross(a, b) > EPS) return CCW;
        if (cross(a, b) < -EPS) return CW;
        if (dot(a, b) < -EPS) return OB;
        if (a.norm() < b.norm()) return OF;

        return OS;
    }

    //交差判定
    bool is_intersect(Point p1, Point p2, Point p3, Point p4) {
        return ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 &&
               ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0;
    }

    //交差判定
    bool is_intersect(Segment s1, Segment s2) {
        return is_intersect(s1.p1, s1.p2, s2.p1, s2.p2);
    }

    //射影を求める
    //pからsに垂直に線を引いたときの座標を返す
    Point project(Segment s, Point p) {
        Vector base = s.p2 - s.p1;
        double r = dot(p - s.p1, base) / norm(base);
        return s.p1 + base * r;
    }

    // 反射
    // pを線分sを対称軸として線対称の位置にある点を求める。
    Point reflect(Segment s, Point p) {
//        return p + (project(s, p) - p) * 2;
        return project(s, p) * 2 - p;
    }


    //距離シリーズ
    //2点間の距離
    double get_distance(Point a, Point b) {
        return abs(a - b);
    }

    // 直線lと点pの距離
    double get_distanceLP(Line l, Point p) {
        return abs(cross(l.p2 - l.p1, p - l.p1) / abs(l.p2 - l.p1));
    }

    // 線分sと点pの距離
    double get_distanceSP(Segment s, Point p) {
        if (dot(s.p2 - s.p1, p - s.p1) < 0.0) return abs(p - s.p1);
        if (dot(s.p1 - s.p2, p - s.p2) < 0.0) return abs(p - s.p2);
        return get_distanceLP(s, p);
    }

    //線分と線分の距離
    double get_distance(Segment s1, Segment s2) {
        if (is_intersect(s1, s2)) return 0.0;
        return min({get_distanceSP(s1, s2.p1),
                    get_distanceSP(s1, s2.p2),
                    get_distanceSP(s2, s1.p1),
                    get_distanceSP(s2, s1.p2),
                   });
    }

    // 線分と線分の交点
    Point get_cross_point(Segment s1, Segment s2) {
//        Vector base = s2.p2 - s2.p1;
//        double d1 = abs(cross(base, s1.p1 - s2.p1));
//        double d2 = abs(cross(base, s1.p2 - s2.p1));
//
//        double t = d1 / (d1 + d2);
//        return s1.p1 + (s1.p2 - s1.p1) * t;

        double d1 = cross(s2.p2 - s2.p1, s2.p1 - s1.p1);
        double d2 = cross(s2.p2 - s2.p1, s1.p2 - s1.p1);
        if (equals(d1, 0) && equals(d2, 0)) return s1.p1;
        if (equals(d2, 0)) throw "no cross point";

        return s1.p1 + (s1.p2 - s1.p1) * d1 / d2;
    }

    struct Circle {
        Point c;
        double r;

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

    //円と線分の交差判定
    bool is_intersect(Circle c, Line l) {
        double d = get_distanceLP(l, c.c);
        return d - c.r < EPS;
    }

    bool is_intersect(Circle c1, Circle c2) {
        double d = get_distance(c1.c, c2.c);
        return d - (c1.r + c2.r) < EPS;
    }

    //円と線分の交点
    pair<Point, Point> get_cross_points(Circle c, Line l) {
//        assert(is_intersect(c, l));
        if (!is_intersect(c, l)) exit(-1);
        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);
    }

    double arg(Vector p) {
        return atan2(p.y, p.x);
    }

    Vector polar(double a, double r) {
        return Point(cos(r) * a, sin(r) * a);
    }

    pair<Point, Point> get_cross_points(Circle c1, Circle c2) {
        assert(is_intersect(c1, 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(c1.c + polar(c1.r, t + a), c1.c + polar(c1.r, t - a));
    }

    using Polygon = vector<Point>;

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

    // 点pが多角形gにあるかを判定
    // 計算量はO(|g|)
    int contains(Polygon g, Point p) {
        int n = g.size();
        bool x = false;
        for (int i = 0; i < n; ++i) {
            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.y > b.y) swap(a, b);
            if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) x = !x;
        }
        return x ? IN : OUT;
    }

    // 点集合sの凸集合を求める。
    // Andrew's Algorithmを使用
    // 計算量はO(|s|log(|s|))
    Polygon get_convex_hull(Polygon s) {
        if (s.size() < 3) return s;
        Polygon u, l;
        sort(s.begin(), s.end());

        u.push_back(s[0]);
        u.push_back(s[1]);
        l.push_back(s[s.size() - 1]);
        l.push_back(s[s.size() - 2]);

        //凸包の上部
        for (int i = 2; i < s.size(); ++i) {
            for (int n = u.size(); n >= 2 && ccw(u[n - 2], u[n - 1], s[i]) == CCW; --n) {
                u.pop_back();
            }
            u.push_back(s[i]);
        }

        //凸包の下部
        for (int i = s.size() - 3; i >= 0; --i) {
            for (int n = l.size(); n >= 2 && ccw(l[n - 2], l[n - 1], s[i]) == CCW; --n) {
                l.pop_back();
            }
            l.push_back(s[i]);
        }
        reverse(l.begin(), l.end());
        for (int i = u.size() - 2; i >= 1; --i) l.push_back(u[i]);

        return l;
    }

    //多角形gの面積を求める
    double get_area(Polygon g) {
        int n = g.size();
        double ret = 0.0;
        for (int i = 0; i < n; ++i) {
            Point a = g[i], b = g[(i + 1) % n];
            double add = (b.y - a.y) * (a.x + b.x) / 2;
            ret += add;
        }

        return fabs(ret);
    }

    std::ostream &operator<<(std::ostream &os, const Point &p) {
//        os << "(" << p.x << ", " << p.y << ")";
        os << "" << p.x << " " << p.y << "";
        return os;
    }

};
using namespace Geometory;

class Solve {
public:
    Int N, K;
    vector<Int> x, y, c;


    // t秒のときに可能かどうか

    bool inner(Circle c1, Circle c2) {
        double d = get_distance(c1.c, c2.c);
        return d + EPS < abs(c1.r - c2.r);
    }

    bool check(double t) {
        vector<Circle> Cs(N);
        for (int i = 0; i < N; ++i) {
            Cs[i].c = Point(x[i], y[i]);
//            Cs[i].r = c[i] * t;
            Cs[i].r = t / c[i];
        }

        auto count = [&](Int i, Int j) -> Int {
            // i, jの交点に肉を置く
            Point p;
            if (!is_intersect(Cs[i], Cs[j])) {
                //交点がない場合はテキトーなところを交点とする
                p = Cs[i].c - Point(0, Cs[i].r);
            } else if (inner(Cs[i], Cs[j])) {
                p = Cs[i].c - Point(0, Cs[i].r);
            } else {
                p = get_cross_points(Cs[i], Cs[j]).first;
            }

            Int ret = 0;
            for (int idx = 0; idx < N; ++idx) {
                double dist = get_distance(p, Point(x[idx], y[idx]));
                if (c[idx] * dist < t + EPS) {
                    ret++;
                }
            }

            return ret;
        };

        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (i != j) {
                    Int tmp = count(i, j);
                    if (tmp >= K) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    void solve() {
        cin >> N >> K;
        x.resize(N);
        y.resize(N);
        c.resize(N);
        for (int i = 0; i < N; ++i) cin >> x[i] >> y[i] >> c[i];

        double ng = 0.0, ok = 1e4;
//        cout << check(1.0) << endl;

        if (K == 1) {
            cout << 0.0 << endl;
            return;
        }
        rep(_, 0, 100) {
            double mid = (ok + ng) / 2;
            if (check(mid)) {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        cout << ok << endl;


    }
};


int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    Solve().solve();


    return 0;
}