Problem:
Warp Drive
The
warp drive
technology is reforming air travel, making the travel times drastically shorter.
Aircraft reaching above the
warp fields
built on the ground surface can be transferred to any desired destination in a twinkling.
With the current immature technology, however, building warp fields is quite expensive.
Our budget allows building only two of them.
Fortunately, the cost does not depend on the locations of the warp fields,
and we can build them anywhere on the ground surface, even at an airport.
Your task is, given locations of airports and a list of one way flights among them, find the best locations to build the two warp fields that give the minimal
average cost
.
The average cost is the root mean square of travel times of all the flights, defined as follows.
Here,
m
is the number of flights and
t
j
is the shortest possible travel time of the
j
-th flight.
Note that the value of
t
j
depends on the locations of the warp fields.
For simplicity, we approximate the surface of the ground by a flat two dimensional plane, and approximate airports, aircraft, and warp fields by points on the plane.
Different flights use different aircraft with possibly different cruising speeds.
Times required for climb, acceleration, deceleration and descent are negligible.
Further, when an aircraft reaches above a warp field, time required after that to its destination is zero.
As is explained below, the airports have integral coordinates. Note, however, that the warp fields can have non-integer coordinates.
Input
The input consists of at most 35 datasets, each in the following format.
n
m
x
1
y
1
...
x
n
y
n
a
1
b
1
v
1
...
a
m
b
m
v
m
n
is the number of airports, and
m
is the number of flights (2 ≤
n
≤ 20, 2 ≤
m
≤ 40).
For each
i
,
x
i
and
y
i
are the coordinates of the
i
-th airport.
x
i
and
y
i
are integers with absolute values at most 1000.
For each
j
,
a
j
and
b
j
are integers between 1 and
n
inclusive, and are the indices of the departure and arrival airports for the
j
-th flight, respectively.
v
j
is the cruising speed for the
j
-th flight, that is, the distance that the aircraft of the flight moves in one time unit.
v
j
is a decimal fraction with two digits after the decimal point (1 ≤
v
j
≤ 10).
The following are guaranteed.
Two different airports have different coordinates.
The departure and arrival airports of any of the flights are different.
Two different flights have different departure airport and/or arrival airport.
The end of the input is indicated by a line containing two zeros.
Output
For each dataset, output the average cost when you place the two warp fields optimally.
The output should not contain an absolute error greater than 10
-6
.
Sample Input
3 4
100 4
100 0
0 0
1 2 1.00
2 1 1.00
3 1 9.99
3 2 9.99
7 6
0 0
1 0
2 0
0 10
1 10
2 10
20 5
1 7 1.00
2 7 1.00
3 7 1.00
4 7 1.00
5 7 1.00
6 7 1.00
4 4
-1 -1
1 -1
-1 1
1 1
1 4 1.10
4 2 2.10
2 3 3.10
3 1 4.10
8 12
-91 0
-62 0
-18 0
2 0
23 0
55 0
63 0
80 0
2 7 3.96
3 2 2.25
2 4 5.48
8 7 
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;

#define rep(i,n) for(ll i=0;i<n;++i)
#define all(a) (a).begin(),(a).end()
ll intpow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll modpow(ll a, ll b, ll p){ ll ans = 1; while(b){ if(b & 1) (ans *= a) %= p; (a *= a) %= p; b /= 2; } return ans; }
template<class T> T div_floor(T a, T b) { return a / b - ((a ^ b) < 0 && a % b); }
template<class T> T div_ceil(T a, T b) { return a / b + ((a ^ b) > 0 && a % b); }
template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }
template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T>
ostream &operator<<(ostream &os, const vector<T> &a){
	if (a.empty()) return os;
	os << a.front();
	for (auto e : a | views::drop(1)){
		os << ' ' << e;
	}
	return os;
}
void dump(auto... vs) {
	((cout << vs << ' '), ...) << endl;
}


// #pragma once

#include <type_traits>
#include <concepts>
#include <compare>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <numeric>
#include <cassert>
#include <ranges>

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

#include<boost/multiprecision/cpp_bin_float.hpp>

#endif

namespace float_geometry {

template<class T>
struct is_floating_point_number : std::bool_constant<false> {};

template<std::floating_point F>
struct is_floating_point_number<F> : std::bool_constant<true> {};

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<D>>> : std::bool_constant<true> {};

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<D>>> : std::bool_constant<true> {};

#endif

template<class F>
concept FloatingPoint = is_floating_point_number<F>::value;

template<FloatingPoint Float>
constexpr Float EPS = Float{1e-8};

template<FloatingPoint Float>
constexpr int sign(const Float &x, Float eps = EPS<Float>){
    return (x < -eps ? -1 : x > eps ? 1 : 0);
}

template<FloatingPoint Float>
struct point {
    Float x, y;
    point () {}
    point (Float _x, Float _y) : x(_x), y(_y) {}
    point &operator+=(const point &r){
        x += r.x;
        y += r.y;
        return *this;
    }
    point &operator-=(const point &r){
        x -= r.x;
        y -= r.y;
        return *this;
    }
    point operator+() const {
        return *this;
    }
    point operator-() const {
        x = -x;
        y = -y;
        return *this;
    }
    point &operator*=(const Float &a){
        x *= a;
        y *= a;
        return *this;
    }
	point &operator/=(const Float &a){
        x /= a;
        y /= a;
        return *this;
    }
    friend point operator+(const point& lhs, const point& rhs){
        return point(lhs) += rhs;
    }
    friend point operator-(const point& lhs, const point& rhs){
        return point(lhs) -= rhs;
    }
    friend point operator*(const point& lhs, const Float& a){
        return point(lhs) *= a;
    }
    friend point operator*(const Float& a, const point& rhs){
        return point(rhs) *= a;
    }
	friend point operator/(const point& lhs, const Float& a){
        return point(lhs) /= a;
    }
    auto operator<=>(const point&) const = default;
    // friend bool operator<(const point &lhs, const point &rhs){
    //     if (lhs.x == rhs.x) return lhs.y < rhs.y;
    //     return lhs.x < rhs.x;
    // }
    // friend bool operator==(const point &lhs, const point &rhs){
    //     return (lhs.x == rhs.x && lhs.y == rhs.y);
    // }
    friend std::ostream &operator<<(std::ostream &os, const point& p){
        return os << p.x << ' ' << p.y;
    }
    friend std::istream &operator>>(std::istream &is, point &a){
        Float _x, _y; is >> _x >> _y;
        a = point(_x, _y);
        return (is);
    }
    friend Float norm(const point &a) {
        return a.x*a.x + a.y*a.y;
    }
    friend Float dot(const point &a, const point &b){
        return a.x*b.x + a.y*b.y;
    }
    friend Float cross(const point &a, const point &b){
        return a.x*b.y - a.y*b.x;
    }
	friend point rot90(const point &a){
		return point(-a.y, a.x);
	}
    friend point rot(const point &a, const Float rad){
        using std::cos, std::sin;
        Float cosrad = cos(rad);
        Float sinrad = sin(rad);
        return point(a.x * cosrad - a.y * sinrad, a.x * sinrad + a.y * cosrad);
    }
    friend Float abs(const point &a){
        using std::sqrt;
        return sqrt(norm(a));
    }

    friend int quadrant_atan2(const point &a){
        // not origin point
        // ceil ( atan2(y,x) / (pi/2) )
		int signx = sign(a.x);
		int signy = sign(a.y);
		if (signx <= 0 && signy <  0) return -1;
		if (signx >  0 && signy <= 0) return  0;
		if (signx >= 0 && signy >  0) return  1;
		if (signx <  0 && signy >= 0) return  2;
        // origin point x == 0 && y == 0
        return 0;
    }

    friend int sign_cross(const point &a, const point &b){
        using std::abs;
        return sign(cross(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(cross(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

    friend int sign_dot(const point &a, const point &b){
        using std::abs;
        return sign(dot(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(dot(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

	friend int ccw(const point &a, point b, point c){
		b -= a;
		c -= a;
		int signcr = sign_cross(b, c);
		if (signcr > 0){
			// ccw       
			//           c
			// a --> b 
			return 1;
		}
		if (signcr < 0){
			// cw
			// a --> b
			//           c
			return -1;
		}
		if (sign_dot(b, c) < 0){
			// c  a --> b
			return 2;
		}
		if (norm(b) < norm(c)){
			// a --> b   c
			return -2;
		}
		// a - c -> b
		return 0;
	}
    friend bool has_common_point(const point &a, const point &b){
        return sign(a.x - b.x) == 0 && sign(a.y - b.y) == 0;
    }

    ld arg() const {
        std::complex<ld> a(x, y);
        return std::arg(a);
    }
};

template<FloatingPoint Float>
struct arg_less {
    constexpr bool operator()(const point<Float> &l, const point<Float> &r){
        using std::atan2;
        return atan2(l.y, l.x) < atan2(r.y, r.x);
    }
};

template<FloatingPoint Float>
void arg_sort(std::vector<point<Float>> &a){
	std::sort(a.begin(), a.end(), arg_less<Float>{});
}


template<FloatingPoint Float>
std::vector<int> upper_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) ptr--;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[i] - a[c], a[c] - a[p]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> lower_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) continue;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[c] - a[p], a[i] - a[c]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	auto upper = upper_convex_hull_index(a);
	auto lower = lower_convex_hull_index(a);
	if (upper.size() == 1u){
		// lower.size() == 1u
		if (a[upper.front()] == a[lower.front()]){
			return {upper.front()};
		}
		return {lower.front(), upper.front()};
	}
	if (a[upper.back()] == a[lower.back()]){
		lower.pop_back();
	}
	lower.insert(lower.end(), upper.rbegin(), upper.rend());
	if (a[upper.front()] == a[lower.front()]) lower.pop_back();
	return lower;
}


template<FloatingPoint Float>
struct line {
	point<Float> end0, end1;
    line () {}
	line (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const line &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const line &a, const line &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const line &a, const line &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const line &a, const point<Float> &b){
		return sign(cross(a.direction(), b - a.end0)) == 0;
	}
	friend bool has_common_point(const line &a, const line &b){
		return !is_parallel(a, b) || has_common_point(a, b.end0);
	}
	friend point<Float> common_point(const line &a, const line &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	friend point<Float> projection(const line &a, const point<Float> &b){
		auto dir = a.direction();
		return a.end0 + dir * (dot(dir, b - a.end0) / norm(dir));
	}
	friend point<Float> reflection(const line &a, const point<Float> &b){
		auto prj = projection(a, b);
		return prj + prj - b;
	}
    friend line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
        auto ctr = (p1 + p2) / Float{2};
        auto dir = rot90(p2 - p1);
        return line<Float>(ctr, ctr + dir);
    }
};

template<FloatingPoint Float>
line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
    auto ctr = (p1 + p2) / Float{2};
    auto dir = rot90(p2 - p1);
    return line<Float>(ctr, ctr + dir);
}


template<FloatingPoint Float>
struct segment {
	point<Float> end0, end1;
    segment () {}
	segment (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const segment &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const segment &a, const segment &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const segment &a, const segment &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const segment &a, const segment &b){
		return ccw(a.end0, a.end1, b.end0) * ccw(a.end0, a.end1, b.end1) <= 0
			&& ccw(b.end0, b.end1, a.end0) * ccw(b.end0, b.end1, a.end1) <= 0;
	}
	friend bool has_common_point(const segment &a, const point<Float> &b){
		return ccw(a.end0, a.end1, b) == 0;
	}
	friend point<Float> common_point(const segment &a, const segment &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			if (has_common_point(a, b.end0)){
				return b.end0;
			}
			if (has_common_point(a, b.end1)){
				return b.end1;
			}
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	line<Float> as_line() const {
		return line<Float>(end0, end1);
	}
};

template<FloatingPoint Float>
struct circle {
    point<Float> center;
    Float radius;
    circle () {}
    circle (const point<Float> &_center, const Float &_radius) : center(_center), radius(_radius) {
        assert(sign(radius) >= 0);
        if (radius < Float{}){
            radius = Float{};
        }
    }
    friend int num_of_common_tangents(const circle &a, const circle &b){
        if (has_common_point(a.center, b.center) && sign(a.radius - b.radius) == 0){
            return 5; // infty
        }
        Float d = abs(a.center - b.center);
        Float r1 = a.radius, r2 = b.radius;
        int sumsign = sign(d - (r1 + r2));
        if (sumsign >= 0) return sumsign + 3;
        using std::abs;
        int diffsign = sign(d - abs(r1 - r2));
        return diffsign + 1;
    }
    friend bool has_common_point(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        return cnt == 1 || cnt == 2 || cnt == 3 || cnt == 5;
    }
    friend bool has_common_point(const circle &c, const line<Float> &l){
        point<Float> p = reflection(l, c.center);
        Float d = abs(c.center, p);
        return sign(c.radius - d) >= 0;
    }
    friend bool has_common_point(const circle &c, const segment<Float> &s){
        return std::ranges::any_of(common_points(c, s.as_line()), [&](auto p){
            return has_common_point(s, p);
        });
    }
    friend bool has_common_point(const circle &c, const point<Float> &p){
        return sign(abs(p - c.center) - c.radius) == 0;
    }
    friend std::vector<point<Float>> common_points(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        assert(cnt != 5); // cannot be same circle
        if (cnt == 0 || cnt == 4){
            return {};
        }
        Float d = abs(a.center - b.center);
        Float x = (d*d + a.radius*a.radius - b.radius*b.radius) / (d + d);
        point<Float> p = a.center + (b.center - a.center) * x / d;
        if (cnt == 1 || cnt == 3 || sign(a.radius - x) <= 0){
            return {p};
        }
        point<Float> v = rot90(b.center - a.center);
        using std::sqrt;
        v *= sqrt(a.radius*a.radius - x*x) / abs(v);
        return {p + v, p - v};
    }
    friend std::vector<point<Float>> common_points(const circle &c, const line<Float> &l) {
        point<Float> p = projection(l, c.center);
        Float d = abs(c.center - p);
        int cnt = sign(c.radius - d) + 1;
        if (cnt == 0){
            return {};
        }
        if (cnt == 1){
            return {p};
        }
        point<Float> v = l.direction();
        using std::sqrt;
        v *= sqrt(c.radius*c.radius - d*d) / abs(v);
        return {p + v, p - v};
    }
};

} // float_geometry

using namespace float_geometry;
using vec=point<ld>;

void solve(ll N,ll M) {
	vector<vec> AP(N);
	rep(i,N){
		cin>>AP[i];
	}
	vector<tuple<ll,ll,ld>> edge(M);
	rep(i,M){
		ll a,b;
		ld v;
		cin>>a>>b>>v;
		a--;
		b--;
		edge[i]={a,b,v};
	}
	auto wp_cost=[&](ll ES)->ld {
		if (ES==0)return 0;
		ld sum=0;
		vec sum_v(0,0);
		rep(j,M){
			if (~ES >> j & 1) continue;
			auto [a,b,v]=edge[j];
			sum+=1/(v*v);
			sum_v+=AP[a]/(v*v);
		}
		sum_v/=sum;
		ld cost=0;
		rep(j,M){
			if (~ES>>j&1)continue;
			auto [a,b,v]=edge[j];
			ld d=(abs(sum_v-AP[a])/v);
			cost+=d*d;
		}
		return cost;
	};
	auto cost_set=[&](ll S)->ld {
		set<ll> ES_set;
		rep(j,M){
			auto [a,b,v]=edge[j];
			if (~S>>a&1)continue;
			circle<ld> cent(AP[a],abs(AP[a]-AP[b]));
			vector<ld> cpt;
			set<ll> same;
			same.insert(j);
			rep(nj,M){
				if (j==nj)continue;
				auto [na,nb,nv]=edge[nj];
				if (~S>>na&1)continue;
				circle<ld> cr(AP[na],abs(AP[na]-AP[nb]));
				if (num_of_common_tangents(cent,cr)==5){
					same.insert(nj);
					continue;
				}
				auto ps=common_points(cent,cr);
				for (auto pp:ps){
					cpt.push_back((pp-AP[a]).arg());
				}
			}
			sort(all(cpt));
			vector<vec> CP;
			if (cpt.size()==0){
				CP.push_back(AP[a]+vec(cent.radius,0));
			}
			else if (cpt.size()==1){
				ld ar=cpt[0]+1.57;
				CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
			}
			else{
				ll sz=cpt.size();
				rep(k,sz){
					ld ar=cpt[k]+cpt[(k+1)%sz];
                    if (k==sz-1)ar+=2*acos(-1);
					ar/=2;
					CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
				}
			}
			for (vec p:CP){
				ll ps=0;
				rep(nj,M){
					if (same.contains(nj))continue;
					auto [na,nb,nv]=edge[nj];
					if (~S>>na&1)continue;
					if (abs(AP[na]-p)<abs(AP[na]-AP[nb])){
						ps^=1LL<<nj;
					}
				}
				ES_set.insert(ps);
				for (ll nj:same){
					ps^=1LL<<nj;
				}
				ES_set.insert(ps);
			}
		}
		ld mc=1e18;
		for (ll es:ES_set){
			ld c=0;
			rep(j,M){
				auto [a,b,v]=edge[j];
				if (~S>>a&1)continue;
				if (es>>j&1)continue;
				ld d=(abs(AP[a]-AP[b])/v);
				c+=d*d;
			}
			c+=wp_cost(es);
			chmin(mc,c);
		}
		return mc;
	};
	auto pt_div=[&]()->ld {
		set<ll> div_set;
		rep(i,N){
			rep(ni,N){
				ll S=0;
				vector<ll> ol;
				rep(j,N){
					ll cw=ccw(AP[i],AP[ni],AP[j]);
					if (cw==1){
						S^=1LL<<j;
					}
					else if (abs(cw)!=1){
						ol.push_back(j);
					}
				}
				if ((AP[i]-AP[ni]).x==0){
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].y<AP[jj].y);
					});
				}
				else{
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].x<AP[jj].x);
					});
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
			}
		}
		ld cost=1e18;
		ll mask=1LL<<N;
		mask--;
		for (ll s:div_set){
			ld c=cost_set(s)+cost_set(s^mask);
			chmin(cost,c);
		}
		return cost;
	};
	ld ans=pt_div();
	ans/=M;
	ans=sqrt(ans);
	cout<<setprecision(15)<<fixed;
	cout<<ans<<endl;
    return;
}


int main() {
    while (true){
		ll N,M;
		cin>>N>>M;
		if (N==0)break;
        solve(N,M);
    }
    return 0;
}
accuracy: 1
time_ms: 3700
memory_kb: 4096
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;

#define rep(i,n) for(ll i=0;i<n;++i)
#define all(a) (a).begin(),(a).end()
ll intpow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll modpow(ll a, ll b, ll p){ ll ans = 1; while(b){ if(b & 1) (ans *= a) %= p; (a *= a) %= p; b /= 2; } return ans; }
template<class T> T div_floor(T a, T b) { return a / b - ((a ^ b) < 0 && a % b); }
template<class T> T div_ceil(T a, T b) { return a / b + ((a ^ b) > 0 && a % b); }
template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }
template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T>
ostream &operator<<(ostream &os, const vector<T> &a){
	if (a.empty()) return os;
	os << a.front();
	for (auto e : a | views::drop(1)){
		os << ' ' << e;
	}
	return os;
}
void dump(auto... vs) {
	((cout << vs << ' '), ...) << endl;
}


// #pragma once

#include <type_traits>
#include <concepts>
#include <compare>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <numeric>
#include <cassert>
#include <ranges>

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

#include<boost/multiprecision/cpp_bin_float.hpp>

#endif

namespace float_geometry {

template<class T>
struct is_floating_point_number : std::bool_constant<false> {};

template<std::floating_point F>
struct is_floating_point_number<F> : std::bool_constant<true> {};

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<D>>> : std::bool_constant<true> {};

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<D>>> : std::bool_constant<true> {};

#endif

template<class F>
concept FloatingPoint = is_floating_point_number<F>::value;

template<FloatingPoint Float>
constexpr Float EPS = Float{1e-8};

template<FloatingPoint Float>
constexpr int sign(const Float &x, Float eps = EPS<Float>){
    return (x < -eps ? -1 : x > eps ? 1 : 0);
}

template<FloatingPoint Float>
struct point {
    Float x, y;
    point () {}
    point (Float _x, Float _y) : x(_x), y(_y) {}
    point &operator+=(const point &r){
        x += r.x;
        y += r.y;
        return *this;
    }
    point &operator-=(const point &r){
        x -= r.x;
        y -= r.y;
        return *this;
    }
    point operator+() const {
        return *this;
    }
    point operator-() const {
        x = -x;
        y = -y;
        return *this;
    }
    point &operator*=(const Float &a){
        x *= a;
        y *= a;
        return *this;
    }
	point &operator/=(const Float &a){
        x /= a;
        y /= a;
        return *this;
    }
    friend point operator+(const point& lhs, const point& rhs){
        return point(lhs) += rhs;
    }
    friend point operator-(const point& lhs, const point& rhs){
        return point(lhs) -= rhs;
    }
    friend point operator*(const point& lhs, const Float& a){
        return point(lhs) *= a;
    }
    friend point operator*(const Float& a, const point& rhs){
        return point(rhs) *= a;
    }
	friend point operator/(const point& lhs, const Float& a){
        return point(lhs) /= a;
    }
    auto operator<=>(const point&) const = default;
    // friend bool operator<(const point &lhs, const point &rhs){
    //     if (lhs.x == rhs.x) return lhs.y < rhs.y;
    //     return lhs.x < rhs.x;
    // }
    // friend bool operator==(const point &lhs, const point &rhs){
    //     return (lhs.x == rhs.x && lhs.y == rhs.y);
    // }
    friend std::ostream &operator<<(std::ostream &os, const point& p){
        return os << p.x << ' ' << p.y;
    }
    friend std::istream &operator>>(std::istream &is, point &a){
        Float _x, _y; is >> _x >> _y;
        a = point(_x, _y);
        return (is);
    }
    friend Float norm(const point &a) {
        return a.x*a.x + a.y*a.y;
    }
    friend Float dot(const point &a, const point &b){
        return a.x*b.x + a.y*b.y;
    }
    friend Float cross(const point &a, const point &b){
        return a.x*b.y - a.y*b.x;
    }
	friend point rot90(const point &a){
		return point(-a.y, a.x);
	}
    friend point rot(const point &a, const Float rad){
        using std::cos, std::sin;
        Float cosrad = cos(rad);
        Float sinrad = sin(rad);
        return point(a.x * cosrad - a.y * sinrad, a.x * sinrad + a.y * cosrad);
    }
    friend Float abs(const point &a){
        using std::sqrt;
        return sqrt(norm(a));
    }

    friend int quadrant_atan2(const point &a){
        // not origin point
        // ceil ( atan2(y,x) / (pi/2) )
		int signx = sign(a.x);
		int signy = sign(a.y);
		if (signx <= 0 && signy <  0) return -1;
		if (signx >  0 && signy <= 0) return  0;
		if (signx >= 0 && signy >  0) return  1;
		if (signx <  0 && signy >= 0) return  2;
        // origin point x == 0 && y == 0
        return 0;
    }

    friend int sign_cross(const point &a, const point &b){
        using std::abs;
        return sign(cross(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(cross(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

    friend int sign_dot(const point &a, const point &b){
        using std::abs;
        return sign(dot(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(dot(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

	friend int ccw(const point &a, point b, point c){
		b -= a;
		c -= a;
		int signcr = sign_cross(b, c);
		if (signcr > 0){
			// ccw       
			//           c
			// a --> b 
			return 1;
		}
		if (signcr < 0){
			// cw
			// a --> b
			//           c
			return -1;
		}
		if (sign_dot(b, c) < 0){
			// c  a --> b
			return 2;
		}
		if (norm(b) < norm(c)){
			// a --> b   c
			return -2;
		}
		// a - c -> b
		return 0;
	}
    friend bool has_common_point(const point &a, const point &b){
        return sign(a.x - b.x) == 0 && sign(a.y - b.y) == 0;
    }

    ld arg() const {
        std::complex<ld> a(x, y);
        return std::arg(a);
    }
};

template<FloatingPoint Float>
struct arg_less {
    constexpr bool operator()(const point<Float> &l, const point<Float> &r){
        using std::atan2;
        return atan2(l.y, l.x) < atan2(r.y, r.x);
    }
};

template<FloatingPoint Float>
void arg_sort(std::vector<point<Float>> &a){
	std::sort(a.begin(), a.end(), arg_less<Float>{});
}


template<FloatingPoint Float>
std::vector<int> upper_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) ptr--;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[i] - a[c], a[c] - a[p]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> lower_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) continue;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[c] - a[p], a[i] - a[c]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	auto upper = upper_convex_hull_index(a);
	auto lower = lower_convex_hull_index(a);
	if (upper.size() == 1u){
		// lower.size() == 1u
		if (a[upper.front()] == a[lower.front()]){
			return {upper.front()};
		}
		return {lower.front(), upper.front()};
	}
	if (a[upper.back()] == a[lower.back()]){
		lower.pop_back();
	}
	lower.insert(lower.end(), upper.rbegin(), upper.rend());
	if (a[upper.front()] == a[lower.front()]) lower.pop_back();
	return lower;
}


template<FloatingPoint Float>
struct line {
	point<Float> end0, end1;
    line () {}
	line (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const line &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const line &a, const line &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const line &a, const line &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const line &a, const point<Float> &b){
		return sign(cross(a.direction(), b - a.end0)) == 0;
	}
	friend bool has_common_point(const line &a, const line &b){
		return !is_parallel(a, b) || has_common_point(a, b.end0);
	}
	friend point<Float> common_point(const line &a, const line &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	friend point<Float> projection(const line &a, const point<Float> &b){
		auto dir = a.direction();
		return a.end0 + dir * (dot(dir, b - a.end0) / norm(dir));
	}
	friend point<Float> reflection(const line &a, const point<Float> &b){
		auto prj = projection(a, b);
		return prj + prj - b;
	}
    friend line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
        auto ctr = (p1 + p2) / Float{2};
        auto dir = rot90(p2 - p1);
        return line<Float>(ctr, ctr + dir);
    }
};

template<FloatingPoint Float>
line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
    auto ctr = (p1 + p2) / Float{2};
    auto dir = rot90(p2 - p1);
    return line<Float>(ctr, ctr + dir);
}


template<FloatingPoint Float>
struct segment {
	point<Float> end0, end1;
    segment () {}
	segment (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const segment &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const segment &a, const segment &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const segment &a, const segment &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const segment &a, const segment &b){
		return ccw(a.end0, a.end1, b.end0) * ccw(a.end0, a.end1, b.end1) <= 0
			&& ccw(b.end0, b.end1, a.end0) * ccw(b.end0, b.end1, a.end1) <= 0;
	}
	friend bool has_common_point(const segment &a, const point<Float> &b){
		return ccw(a.end0, a.end1, b) == 0;
	}
	friend point<Float> common_point(const segment &a, const segment &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			if (has_common_point(a, b.end0)){
				return b.end0;
			}
			if (has_common_point(a, b.end1)){
				return b.end1;
			}
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	line<Float> as_line() const {
		return line<Float>(end0, end1);
	}
};

template<FloatingPoint Float>
struct circle {
    point<Float> center;
    Float radius;
    circle () {}
    circle (const point<Float> &_center, const Float &_radius) : center(_center), radius(_radius) {
        assert(sign(radius) >= 0);
        if (radius < Float{}){
            radius = Float{};
        }
    }
    friend int num_of_common_tangents(const circle &a, const circle &b){
        if (has_common_point(a.center, b.center) && sign(a.radius - b.radius) == 0){
            return 5; // infty
        }
        Float d = abs(a.center - b.center);
        Float r1 = a.radius, r2 = b.radius;
        int sumsign = sign(d - (r1 + r2));
        if (sumsign >= 0) return sumsign + 3;
        using std::abs;
        int diffsign = sign(d - abs(r1 - r2));
        return diffsign + 1;
    }
    friend bool has_common_point(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        return cnt == 1 || cnt == 2 || cnt == 3 || cnt == 5;
    }
    friend bool has_common_point(const circle &c, const line<Float> &l){
        point<Float> p = reflection(l, c.center);
        Float d = abs(c.center, p);
        return sign(c.radius - d) >= 0;
    }
    friend bool has_common_point(const circle &c, const segment<Float> &s){
        return std::ranges::any_of(common_points(c, s.as_line()), [&](auto p){
            return has_common_point(s, p);
        });
    }
    friend bool has_common_point(const circle &c, const point<Float> &p){
        return sign(abs(p - c.center) - c.radius) == 0;
    }
    friend std::vector<point<Float>> common_points(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        assert(cnt != 5); // cannot be same circle
        if (cnt == 0 || cnt == 4){
            return {};
        }
        Float d = abs(a.center - b.center);
        Float x = (d*d + a.radius*a.radius - b.radius*b.radius) / (d + d);
        point<Float> p = a.center + (b.center - a.center) * x / d;
        if (cnt == 1 || cnt == 3 || sign(a.radius - x) <= 0){
            return {p};
        }
        point<Float> v = rot90(b.center - a.center);
        using std::sqrt;
        v *= sqrt(a.radius*a.radius - x*x) / abs(v);
        return {p + v, p - v};
    }
    friend std::vector<point<Float>> common_points(const circle &c, const line<Float> &l) {
        point<Float> p = projection(l, c.center);
        Float d = abs(c.center - p);
        int cnt = sign(c.radius - d) + 1;
        if (cnt == 0){
            return {};
        }
        if (cnt == 1){
            return {p};
        }
        point<Float> v = l.direction();
        using std::sqrt;
        v *= sqrt(c.radius*c.radius - d*d) / abs(v);
        return {p + v, p - v};
    }
};

} // float_geometry

using namespace float_geometry;
using vec=point<ld>;

void solve(ll N,ll M) {
	vector<vec> AP(N);
	rep(i,N){
		cin>>AP[i];
	}
	vector<tuple<ll,ll,ld>> edge(M);
	rep(i,M){
		ll a,b;
		ld v;
		cin>>a>>b>>v;
		a--;
		b--;
		edge[i]={a,b,v};
	}
	auto wp_cost=[&](ll ES)->ld {
		if (ES==0)return 0;
		ld sum=0;
		vec sum_v(0,0);
		rep(j,M){
			if (~ES >> j & 1) continue;
			auto [a,b,v]=edge[j];
			sum+=1/(v*v);
			sum_v+=AP[a]/(v*v);
		}
		sum_v/=sum;
		ld cost=0;
		rep(j,M){
			if (~ES>>j&1)continue;
			auto [a,b,v]=edge[j];
			ld d=(abs(sum_v-AP[a])/v);
			cost+=d*d;
		}
		return cost;
	};
	auto cost_set=[&](ll S)->ld {
		set<ll> ES_set;
		rep(j,M){
			auto [a,b,v]=edge[j];
			if (~S>>a&1)continue;
			circle<ld> cent(AP[a],abs(AP[a]-AP[b]));
			vector<ld> cpt;
			set<ll> same;
			same.insert(j);
			rep(nj,M){
				if (j==nj)continue;
				auto [na,nb,nv]=edge[nj];
				if (~S>>na&1)continue;
				circle<ld> cr(AP[na],abs(AP[na]-AP[nb]));
				if (num_of_common_tangents(cent,cr)==5){
					same.insert(nj);
					continue;
				}
				auto ps=common_points(cent,cr);
				for (auto pp:ps){
					cpt.push_back((pp-AP[a]).arg());
				}
			}
			sort(all(cpt));
			vector<vec> CP;
			if (cpt.size()==0){
				CP.push_back(AP[a]+vec(cent.radius,0));
			}
			else if (cpt.size()==1){
				ld ar=cpt[0]+1.57;
				CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
			}
			else{
				ll sz=cpt.size();
				rep(k,sz){
					ld ar=cpt[k]+cpt[(k+1)%sz];
					ar/=2;
					CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
				}
			}
			for (vec p:CP){
				ll ps=0;
				rep(nj,M){
					if (same.contains(nj))continue;
					auto [na,nb,nv]=edge[nj];
					if (~S>>na&1)continue;
					if (abs(AP[na]-p)<abs(AP[na]-AP[nb])){
						ps^=1LL<<nj;
					}
				}
				ES_set.insert(ps);
				for (ll nj:same){
					ps^=1LL<<nj;
				}
				ES_set.insert(ps);
			}
		}
		ld mc=1e18;
		for (ll es:ES_set){
			ld c=0;
			rep(j,M){
				auto [a,b,v]=edge[j];
				if (~S>>a&1)continue;
				if (es>>j&1)continue;
				ld d=(abs(AP[a]-AP[b])/v);
				c+=d*d;
			}
			c+=wp_cost(es);
			chmin(mc,c);
		}
		return mc;
	};
	auto pt_div=[&]()->ld {
		set<ll> div_set;
		rep(i,N){
			rep(ni,N){
				ll S=0;
				vector<ll> ol;
				rep(j,N){
					ll cw=ccw(AP[i],AP[ni],AP[j]);
					if (cw==1){
						S^=1LL<<j;
					}
					else if (abs(cw)!=1){
						ol.push_back(j);
					}
				}
				if ((AP[i]-AP[ni]).x==0){
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].y<AP[jj].y);
					});
				}
				else{
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].x<AP[jj].x);
					});
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
			}
		}
		ld cost=1e18;
		ll mask=1LL<<N;
		mask--;
		for (ll s:div_set){
			ld c=cost_set(s)+cost_set(s^mask);
			chmin(cost,c);
		}
		return cost;
	};
	ld ans=pt_div();
	ans/=M;
	ans=sqrt(ans);
	cout<<setprecision(15)<<fixed;
	cout<<ans<<endl;
    return;
}


int main() {
    while (true){
		ll N,M;
		cin>>N>>M;
		if (N==0)break;
        solve(N,M);
    }
    return 0;
}
accuracy: 0.5
time_ms: 3640
memory_kb: 4096
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;

#define rep(i,n) for(ll i=0;i<n;++i)
#define all(a) (a).begin(),(a).end()
ll intpow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll modpow(ll a, ll b, ll p){ ll ans = 1; while(b){ if(b & 1) (ans *= a) %= p; (a *= a) %= p; b /= 2; } return ans; }
template<class T> T div_floor(T a, T b) { return a / b - ((a ^ b) < 0 && a % b); }
template<class T> T div_ceil(T a, T b) { return a / b + ((a ^ b) > 0 && a % b); }
template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }
template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T>
ostream &operator<<(ostream &os, const vector<T> &a){
	if (a.empty()) return os;
	os << a.front();
	for (auto e : a | views::drop(1)){
		os << ' ' << e;
	}
	return os;
}
void dump(auto... vs) {
	((cout << vs << ' '), ...) << endl;
}


// #pragma once

#include <type_traits>
#include <concepts>
#include <compare>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <numeric>
#include <cassert>
#include <ranges>

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

#include<boost/multiprecision/cpp_bin_float.hpp>

#endif

namespace float_geometry {

template<class T>
struct is_floating_point_number : std::bool_constant<false> {};

template<std::floating_point F>
struct is_floating_point_number<F> : std::bool_constant<true> {};

#if __has_include(<boost/multiprecision/cpp_bin_float.hpp>)

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<D>>> : std::bool_constant<true> {};

template<unsigned D>
struct is_floating_point_number<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<D>>> : std::bool_constant<true> {};

#endif

template<class F>
concept FloatingPoint = is_floating_point_number<F>::value;

template<FloatingPoint Float>
constexpr Float EPS = Float{1e-9};

template<FloatingPoint Float>
constexpr int sign(const Float &x, Float eps = EPS<Float>){
    return (x < -eps ? -1 : x > eps ? 1 : 0);
}

template<FloatingPoint Float>
struct point {
    Float x, y;
    point () {}
    point (Float _x, Float _y) : x(_x), y(_y) {}
    point &operator+=(const point &r){
        x += r.x;
        y += r.y;
        return *this;
    }
    point &operator-=(const point &r){
        x -= r.x;
        y -= r.y;
        return *this;
    }
    point operator+() const {
        return *this;
    }
    point operator-() const {
        x = -x;
        y = -y;
        return *this;
    }
    point &operator*=(const Float &a){
        x *= a;
        y *= a;
        return *this;
    }
	point &operator/=(const Float &a){
        x /= a;
        y /= a;
        return *this;
    }
    friend point operator+(const point& lhs, const point& rhs){
        return point(lhs) += rhs;
    }
    friend point operator-(const point& lhs, const point& rhs){
        return point(lhs) -= rhs;
    }
    friend point operator*(const point& lhs, const Float& a){
        return point(lhs) *= a;
    }
    friend point operator*(const Float& a, const point& rhs){
        return point(rhs) *= a;
    }
	friend point operator/(const point& lhs, const Float& a){
        return point(lhs) /= a;
    }
    auto operator<=>(const point&) const = default;
    // friend bool operator<(const point &lhs, const point &rhs){
    //     if (lhs.x == rhs.x) return lhs.y < rhs.y;
    //     return lhs.x < rhs.x;
    // }
    // friend bool operator==(const point &lhs, const point &rhs){
    //     return (lhs.x == rhs.x && lhs.y == rhs.y);
    // }
    friend std::ostream &operator<<(std::ostream &os, const point& p){
        return os << p.x << ' ' << p.y;
    }
    friend std::istream &operator>>(std::istream &is, point &a){
        Float _x, _y; is >> _x >> _y;
        a = point(_x, _y);
        return (is);
    }
    friend Float norm(const point &a) {
        return a.x*a.x + a.y*a.y;
    }
    friend Float dot(const point &a, const point &b){
        return a.x*b.x + a.y*b.y;
    }
    friend Float cross(const point &a, const point &b){
        return a.x*b.y - a.y*b.x;
    }
	friend point rot90(const point &a){
		return point(-a.y, a.x);
	}
    friend point rot(const point &a, const Float rad){
        using std::cos, std::sin;
        Float cosrad = cos(rad);
        Float sinrad = sin(rad);
        return point(a.x * cosrad - a.y * sinrad, a.x * sinrad + a.y * cosrad);
    }
    friend Float abs(const point &a){
        using std::sqrt;
        return sqrt(norm(a));
    }

    friend int quadrant_atan2(const point &a){
        // not origin point
        // ceil ( atan2(y,x) / (pi/2) )
		int signx = sign(a.x);
		int signy = sign(a.y);
		if (signx <= 0 && signy <  0) return -1;
		if (signx >  0 && signy <= 0) return  0;
		if (signx >= 0 && signy >  0) return  1;
		if (signx <  0 && signy >= 0) return  2;
        // origin point x == 0 && y == 0
        return 0;
    }

    friend int sign_cross(const point &a, const point &b){
        using std::abs;
        return sign(cross(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(cross(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

    friend int sign_dot(const point &a, const point &b){
        using std::abs;
        return sign(dot(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
        // return sign(dot(a, b), EPS<Float> * (abs<Float>(a.x) + abs<Float>(a.y) + abs<Float>(b.x) + abs<Float>(b.y)));
    }

	friend int ccw(const point &a, point b, point c){
		b -= a;
		c -= a;
		int signcr = sign_cross(b, c);
		if (signcr > 0){
			// ccw       
			//           c
			// a --> b 
			return 1;
		}
		if (signcr < 0){
			// cw
			// a --> b
			//           c
			return -1;
		}
		if (sign_dot(b, c) < 0){
			// c  a --> b
			return 2;
		}
		if (norm(b) < norm(c)){
			// a --> b   c
			return -2;
		}
		// a - c -> b
		return 0;
	}
    friend bool has_common_point(const point &a, const point &b){
        return sign(a.x - b.x) == 0 && sign(a.y - b.y) == 0;
    }

    ld arg() const {
        std::complex<ld> a(x, y);
        return std::arg(a);
    }
};

template<FloatingPoint Float>
struct arg_less {
    constexpr bool operator()(const point<Float> &l, const point<Float> &r){
        using std::atan2;
        return atan2(l.y, l.x) < atan2(r.y, r.x);
    }
};

template<FloatingPoint Float>
void arg_sort(std::vector<point<Float>> &a){
	std::sort(a.begin(), a.end(), arg_less<Float>{});
}


template<FloatingPoint Float>
std::vector<int> upper_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) ptr--;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[i] - a[c], a[c] - a[p]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> lower_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) continue;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[c] - a[p], a[i] - a[c]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<FloatingPoint Float>
std::vector<int> convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	auto upper = upper_convex_hull_index(a);
	auto lower = lower_convex_hull_index(a);
	if (upper.size() == 1u){
		// lower.size() == 1u
		if (a[upper.front()] == a[lower.front()]){
			return {upper.front()};
		}
		return {lower.front(), upper.front()};
	}
	if (a[upper.back()] == a[lower.back()]){
		lower.pop_back();
	}
	lower.insert(lower.end(), upper.rbegin(), upper.rend());
	if (a[upper.front()] == a[lower.front()]) lower.pop_back();
	return lower;
}


template<FloatingPoint Float>
struct line {
	point<Float> end0, end1;
    line () {}
	line (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const line &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const line &a, const line &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const line &a, const line &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const line &a, const point<Float> &b){
		return sign(cross(a.direction(), b - a.end0)) == 0;
	}
	friend bool has_common_point(const line &a, const line &b){
		return !is_parallel(a, b) || has_common_point(a, b.end0);
	}
	friend point<Float> common_point(const line &a, const line &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	friend point<Float> projection(const line &a, const point<Float> &b){
		auto dir = a.direction();
		return a.end0 + dir * (dot(dir, b - a.end0) / norm(dir));
	}
	friend point<Float> reflection(const line &a, const point<Float> &b){
		auto prj = projection(a, b);
		return prj + prj - b;
	}
    friend line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
        auto ctr = (p1 + p2) / Float{2};
        auto dir = rot90(p2 - p1);
        return line<Float>(ctr, ctr + dir);
    }
};

template<FloatingPoint Float>
line<Float> perpendicular_bisector(const point<Float> &p1, const point<Float> &p2){
    auto ctr = (p1 + p2) / Float{2};
    auto dir = rot90(p2 - p1);
    return line<Float>(ctr, ctr + dir);
}


template<FloatingPoint Float>
struct segment {
	point<Float> end0, end1;
    segment () {}
	segment (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		assert(end0 != end1);
	}
	// auto operator<=>(const segment &) const = default;
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const segment &a, const segment &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const segment &a, const segment &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const segment &a, const segment &b){
		return ccw(a.end0, a.end1, b.end0) * ccw(a.end0, a.end1, b.end1) <= 0
			&& ccw(b.end0, b.end1, a.end0) * ccw(b.end0, b.end1, a.end1) <= 0;
	}
	friend bool has_common_point(const segment &a, const point<Float> &b){
		return ccw(a.end0, a.end1, b) == 0;
	}
	friend point<Float> common_point(const segment &a, const segment &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			if (has_common_point(a, b.end0)){
				return b.end0;
			}
			if (has_common_point(a, b.end1)){
				return b.end1;
			}
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	line<Float> as_line() const {
		return line<Float>(end0, end1);
	}
};

template<FloatingPoint Float>
struct circle {
    point<Float> center;
    Float radius;
    circle () {}
    circle (const point<Float> &_center, const Float &_radius) : center(_center), radius(_radius) {
        assert(sign(radius) >= 0);
        if (radius < Float{}){
            radius = Float{};
        }
    }
    friend int num_of_common_tangents(const circle &a, const circle &b){
        if (has_common_point(a.center, b.center) && sign(a.radius - b.radius) == 0){
            return 5; // infty
        }
        Float d = abs(a.center - b.center);
        Float r1 = a.radius, r2 = b.radius;
        int sumsign = sign(d - (r1 + r2));
        if (sumsign >= 0) return sumsign + 3;
        using std::abs;
        int diffsign = sign(d - abs(r1 - r2));
        return diffsign + 1;
    }
    friend bool has_common_point(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        return cnt == 1 || cnt == 2 || cnt == 3 || cnt == 5;
    }
    friend bool has_common_point(const circle &c, const line<Float> &l){
        point<Float> p = reflection(l, c.center);
        Float d = abs(c.center, p);
        return sign(c.radius - d) >= 0;
    }
    friend bool has_common_point(const circle &c, const segment<Float> &s){
        return std::ranges::any_of(common_points(c, s.as_line()), [&](auto p){
            return has_common_point(s, p);
        });
    }
    friend bool has_common_point(const circle &c, const point<Float> &p){
        return sign(abs(p - c.center) - c.radius) == 0;
    }
    friend std::vector<point<Float>> common_points(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        assert(cnt != 5); // cannot be same circle
        if (cnt == 0 || cnt == 4){
            return {};
        }
        Float d = abs(a.center - b.center);
        Float x = (d*d + a.radius*a.radius - b.radius*b.radius) / (d + d);
        point<Float> p = a.center + (b.center - a.center) * x / d;
        if (cnt == 1 || cnt == 3 || sign(a.radius - x) <= 0){
            return {p};
        }
        point<Float> v = rot90(b.center - a.center);
        using std::sqrt;
        v *= sqrt(a.radius*a.radius - x*x) / abs(v);
        return {p + v, p - v};
    }
    friend std::vector<point<Float>> common_points(const circle &c, const line<Float> &l) {
        point<Float> p = projection(l, c.center);
        Float d = abs(c.center - p);
        int cnt = sign(c.radius - d) + 1;
        if (cnt == 0){
            return {};
        }
        if (cnt == 1){
            return {p};
        }
        point<Float> v = l.direction();
        using std::sqrt;
        v *= sqrt(c.radius*c.radius - d*d) / abs(v);
        return {p + v, p - v};
    }
};

} // float_geometry

using namespace float_geometry;
using vec=point<ld>;

void solve(ll N,ll M) {
	vector<vec> AP(N);
	rep(i,N){
		cin>>AP[i];
	}
	vector<tuple<ll,ll,ld>> edge(M);
	rep(i,M){
		ll a,b;
		ld v;
		cin>>a>>b>>v;
		a--;
		b--;
		edge[i]={a,b,v};
	}
	auto wp_cost=[&](ll ES)->ld {
		if (ES==0)return 0;
		ld sum=0;
		vec sum_v(0,0);
		rep(j,M){
			if (~ES >> j & 1) continue;
			auto [a,b,v]=edge[j];
			sum+=1/(v*v);
			sum_v+=AP[a]/(v*v);
		}
		sum_v/=sum;
		ld cost=0;
		rep(j,M){
			if (~ES>>j&1)continue;
			auto [a,b,v]=edge[j];
			ld d=(abs(sum_v-AP[a])/v);
			cost+=d*d;
		}
		return cost;
	};
	auto cost_set=[&](ll S)->ld {
		if (S == 0) return 0;
		set<ll> ES_set;
		rep(j,M){
			auto [a,b,v]=edge[j];
			if (~S>>a&1)continue;
			circle<ld> cent(AP[a],abs(AP[a]-AP[b]));
			vector<ld> cpt;
			set<ll> same;
			same.insert(j);
			rep(nj,M){
				if (j==nj)continue;
				auto [na,nb,nv]=edge[nj];
				if (~S>>na&1)continue;
				circle<ld> cr(AP[na],abs(AP[na]-AP[nb]));
				if (num_of_common_tangents(cent,cr)==5){
					same.insert(nj);
					continue;
				}
				auto ps=common_points(cent,cr);
				for (auto pp:ps){
					cpt.push_back((pp-AP[a]).arg());
				}
			}
			sort(all(cpt));
			vector<vec> CP;
			if (cpt.size()==0){
				CP.push_back(AP[a]+vec(cent.radius,0));
			}
			else if (cpt.size()==1){
				ld ar=cpt[0]+acos(-1);
				CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
			}
			else{
				ll sz=cpt.size();
				rep(k,sz){
					ld ar=cpt[k]+(k == sz-1 ? cpt[0]+acos(-1)*2 : cpt[k+1]);
					ar/=2;
					CP.push_back(AP[a]+rot(vec(cent.radius,0),ar));
				}
			}
			for (vec p:CP){
				ll ps=0;
				rep(nj,M){
					if (same.contains(nj))continue;
					auto [na,nb,nv]=edge[nj];
					if (~S>>na&1)continue;
					if (abs(AP[na]-p)<abs(AP[na]-AP[nb])){
						ps^=1LL<<nj;
					}
				}
				ES_set.insert(ps);
				for (ll nj:same){
					ps^=1LL<<nj;
				}
				ES_set.insert(ps);
			}
		}
		ld mc=1e18;
		for (ll es:ES_set){
			ld c=0;
			rep(j,M){
				auto [a,b,v]=edge[j];
				if (~S>>a&1)continue;
				if (es>>j&1)continue;
				ld d=(abs(AP[a]-AP[b])/v);
				c+=d*d;
			}
			c+=wp_cost(es);
			chmin(mc,c);
		}
		return mc;
	};
	auto pt_div=[&]()->ld {
		set<ll> div_set;
		rep(i,N){
			rep(ni,N){
				ll S=0;
				vector<ll> ol;
				rep(j,N){
					ll cw=ccw(AP[i],AP[ni],AP[j]);
					if (cw==1){
						S^=1LL<<j;
					}
					else if (abs(cw)!=1){
						ol.push_back(j);
					}
				}
				if ((AP[i]-AP[ni]).x==0){
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].y<AP[jj].y);
					});
				}
				else{
					sort(all(ol),[&](ll ii,ll jj){
						return (AP[ii].x<AP[jj].x);
					});
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
				for (ll k:ol){
					div_set.insert(S);
					S^=1LL<<k;
				}
			}
		}
		ld cost=1e18;
		ll mask=(1LL<<N)-1;
		for (ll s:div_set){
			ld c=cost_set(s)+cost_set(s^mask);
			chmin(cost,c);
		}
		return cost;
	};
	ld ans=pt_div();
	ans/=M;
	ans=sqrt(ans);
	cout<<setprecision(15)<<fixed;
	cout<<ans<<endl;
    return;
}


int main() {
    while (true){
		ll N,M;
		cin>>N>>M;
		if (N==0)break;
        solve(N,M);
    }
    return 0;
}
accuracy: 1
time_ms: 3700
memory_kb: 4096
final_rank: 5

code_snippet: #include<bits/stdc++.h>

#define rep(i,s,n) for (int i = s; i < (int)(n); i++)
#define rrep(i,s,n) for (int i = (int)(n)-1; i >= (int)(s); i--)
#define all(v) v.begin(),v.end()

using ll = long long;
using ld = long double;
using ull = unsigned long long;

template<typename T> bool chmin(T &a, const T &b){
    if (a <= b) return false;
    a = b;
    return true;
}
template<typename T> bool chmax(T &a, const T &b){
    if (a >= b) return false;
    a = b;
    return true;
}

namespace lib{

using namespace std;

} // namespace lib;

using namespace lib;

namespace lib {

using vec = complex<ld>;
const ld eps = 1e-7;

void ldout(int len = 15){
    cout << fixed << setprecision(len);
}

int sgn(ld a) {
    return (a < -eps) ? -1 : (a > eps) ? 1 : 0;
}

ld dot(const vec &a, const vec &b){
    return (conj(a) * b).real();
}

ld cross(const vec &a, const vec &b){
    return (conj(a) * b).imag();
}

int isp(const vec &a, const vec &b, const vec &c) {
    int cross_sgn = sgn(cross(b - a, c - a));
    if(cross_sgn == 0) {
        if(sgn(dot(b - a, c - a)) < 0) return -2;
        if(sgn(dot(a - b, c - b)) < 0) return 2;
    }
    return cross_sgn;
}

vec rot90(const vec &a) {
    return {-a.imag(), a.real()};
}

vec rot(const vec &a, ld rad){
    return a * vec(cosl(rad),sinl(rad));
}

bool comp_for_argument_sort(const vec &lhs, const vec &rhs){
    //if (abs(arg(lhs)-arg(rhs)) < eps) return false; // need ?
    return arg(lhs) < arg(rhs);
}

} // namespace lib


namespace lib {

struct line {
    vec a, b;
};

vec proj(const line &l, const vec &p) {
    vec ab = l.b - l.a;
    return l.a + ab * (dot(ab, p - l.a) / norm(ab));
}

vec refl(const line &l, const vec &p) {
    return proj(l, p) * ld(2) - p;
}

int intersection(const line &a, const line &b) {
    if(sgn(cross(a.b - a.a, b.a - b.b)) != 0) {
        if(sgn(dot(a.b - a.a, b.a - b.b)) == 0) {
            return 1;
        }
        return 0;
    }
    else if(sgn(cross(a.b - a.a, b.a - a.a)) != 0) {
        return 2;
    }
    else {
        return 3;
    }
}

ld dist(const line &a, const vec &p) {
    return abs(cross(p - a.a, a.b - a.a) / abs(a.b - a.a));
}

vec cross_point(const line &a, const line &b) {
    assert(intersection(a, b) < 2);
    return a.a + (a.b - a.a) * cross(b.a - a.a, b.b - b.a) / cross(a.b - a.a, b.b - b.a);
}

}

namespace lib {

struct circle {
    vec c;
    ld r;
};

int intersection(const circle &c1, const circle &c2) {
    ld d = abs(c1.c - c2.c);
    ld r1 = c1.r;
    ld r2 = c2.r;
    if(r1 < r2) std::swap(r1, r2);
    if(sgn(d - (r1 + r2)) > 0) {
        return 4;
    }
    else if(sgn(d - (r1 + r2) == 0)) {
        return 3;
    }
    else if(sgn(d - r1 + r2) > 0) {
        return 2;
    }
    else if(sgn(d - r1 + r2) == 0) {
        return 1;
    }
    else return 0;
}

circle incircle_of_triangle(const vec &a, const vec &b, const vec &c) {
    ld A = abs(b - c), B = abs(c - a), C = abs(a - b);
    vec in = A * a + B * b + C * c;
    in /= A + B + C;
    ld r = abs(cross(in - a, b - a) / abs(b - a));
    return {in, r};
}

circle circumscribed_circle_of_triangle(const vec &a, const vec &b, const vec &c) {
    line p = {(a + b)/ld(2.0), (a + b)/ld(2.0)+rot90(b - a)};
    line q = {(b + c)/ld(2.0), (b + c)/ld(2.0)+rot90(c - b)};
    vec cross = cross_point(p, q);
    return {cross, abs(a-cross)};
}

vector<vec> cross_point(const circle &c, const line &l) {
    vector<vec> ps;
    ld d = dist(l, c.c);
    if(sgn(d - c.r) == 0) ps.emplace_back(proj(l, c.c));
    else if(sgn(d - c.r) < 0) {
        vec p = proj(l, c.c);
        vec v = l.b - l.a;
        v *= sqrt(max(c.r*c.r - d * d,  ld(0))) / abs(v);
        ps.emplace_back(p + v);
        ps.emplace_back(p - v);
    }
    return ps;
}

vector<vec> cross_point(const circle &c1, const circle &c2) {
    vector<vec> ps;
    int cnt_tangent = intersection(c1, c2);
    if(cnt_tangent == 0 || cnt_tangent == 4) return {};
    ld d = abs(c2.c - c1.c);
    ld x = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
    vec p = c1.c + (c2.c - c1.c) * x / d;
    vec v = rot90(c2.c - c1.c);
    if(cnt_tangent == 1 || cnt_tangent == 3) ps.emplace_back(p);
    else {
        v *= sqrt(max(c1.r * c1.r - x * x, ld(0))) / abs(v);
        ps.emplace_back(p + v);
        ps.emplace_back(p - v);
    }
    return ps;
}

}


template<typename T>
void vout(const vector<T> &a){
    rep(i,0,a.size()){
        cout << a[i] << " \n"[i == a.size()-1];
    } cout << endl;
}

bool on_line(const line &a, const vec &v){
    return sgn(dist(a,v)) == 0;
}

bool same_line(const line &a, const line &b){
    return on_line(a,b.a) && on_line(a,b.b);
}

bool same_circle(const circle &a, const circle &b){
    return sgn(abs(a.c-b.c)) == 0 && sgn(abs(a.r-b.r)) == 0;
}

ll gcd_safe(ll a, ll b){
    return gcd(abs(a),abs(b));
}

struct Line{
    ll a, b, c; // ax + by = c
    ll xp, yp, xq, yq;
    void norm(){ // a >= 0, if (a == 0) -> b >= 0, gcd(a,b,c) = 1
        if (a < 0) a = -a, b = -b, c = -c;
        if (a == 0) if (b < 0) b = -b, c = -c;
        ll g = gcd_safe(gcd_safe(a,b),c);
        a /= g, b /= g, c /= g;
    }
    Line (ll _a = 1, ll _b = 0, ll _c = 0) : a(_a), b(_b), c(_c) {
        assert(_a != 0 || _b != 0);
        norm();
    }
    Line (ll x1, ll y1, ll x2, ll y2){ // --- (x1,y1) --- (x2,y2) ---
        assert(x1 != x2 || y1 != y2);
        ll wx = x2 - x1, wy = y2 - y1;
        ll wg = gcd_safe(wx,wy);
        a = wy / wg, b = -wx / wg;
        c = a * x1 + b * y1;
        norm();
        xp = x1, yp = y1, xq = x2, yq = y2;
    }
    bool operator<(const Line &rhs) const { // to use set or map for Line
        if (a == rhs.a){
            if (b == rhs.b) return c < rhs.c;
            return b < rhs.b;
        }
        return a < rhs.a;
    }
};

using P = pair<int,int>;

void input_point(int n, int m, vector<vec> &a, vector<line> &lines, vector<circle> &cirs,
    vector<P> &es, vector<ld> &vrs, vector<ll> &nmsk){
    vector<ll> xs(n), ys(n);
    rep(i,0,n){
        cin >> xs[i] >> ys[i];
        a.emplace_back(rot(vec(xs[i],ys[i]),1));
    }
    set<Line> prelines;
    rep(i,0,n-1) rep(j,i+1,n) prelines.insert(Line(xs[i],ys[i],xs[j],ys[j]));
    for (auto cl : prelines){
        vec xy1(cl.xp,cl.yp);
        vec xy2(cl.xq,cl.yq);
        lines.push_back({rot(xy1,1),rot(xy2,1)});
    }
    set<P> cirst;
    rep(i,0,m){
        int u, v; cin >> u >> v; u--, v--;
        ld vr; cin >> vr;
        es[i] = P(u,v);
        vrs[i] = 1/vr/vr;
        nmsk[u] |= (1LL << i);
        int dx = xs[u] - xs[v];
        int dy = ys[u] - ys[v];
        cirst.insert(make_pair(u,dx*dx+dy*dy));
    }
    for (auto p : cirst){
        cirs.push_back({a[p.first],sqrtl(p.second)});
    }
}

void solve1(int n, int m){
    ldout();
    vector<vec> a;
    vector<line> lines;
    vector<circle> cirs;
    vector<P> es(m);
    vector<ld> vrs(m);
    vector<ll> nmsk(n,0);
    input_point(n,m,a,lines,cirs,es,vrs,nmsk);
    cirs.push_back({vec(0,0),5000}); // add large circle
    int ns = cirs.size();
    using pvt = pair<vec,int>;
    // enumerate x, leftmost point of circle, rightmost point of circle, cross point of two circles
    vector<pvt> vs;
    rep(i,0,ns){
        vs.emplace_back(pvt(cirs[i].c - vec(cirs[i].r,0), 0));
        vs.emplace_back(pvt(cirs[i].c + vec(cirs[i].r,0), 1));
        rep(j,i+1,ns){
            for (auto p : cross_point(cirs[i],cirs[j])){
                vs.emplace_back(pvt(p,2));
            }
        }
    }
    sort(all(vs),[&](pvt l, pvt r){
        if (sgn(abs(l.first-r.first)) == 0) return false;
        return l.first.real() < r.first.real();
    });
    // unique x
    vector<pvt> nvs;
    vec mae(-100000,0);
    for (pvt vt : vs){
        if (sgn(abs(mae-vt.first)) == 0) continue;
        nvs.emplace_back(vt);
        mae = vt.first;
    }
    swap(nvs,vs);
    int ms = vs.size();
    vector<vec> pnt;
    rep(i,0,ms){
        if (vs[i].second < 2) continue;
        int cnt = 0;
        rep(j,0,ns) if (sgn(cirs[j].r - abs(cirs[j].c - vs[i].first)) == 0) cnt++;
        vs[i].second = cnt;
        pnt.emplace_back(vs[i].first);
    }
    // enumerate y corresponding each x
    vector<vector<pvt>> ver(ms);
    rep(i,0,ms){
        line l({vec(vs[i].first.real(),0),vec(vs[i].first.real(),1)});
        ver[i].emplace_back(vs[i]);
        rep(j,0,ns){
            for (auto p : cross_point(cirs[j],l)){
                if (sgn(abs(vs[i].first-p)) == 0) continue;
                ver[i].emplace_back(pvt(p,-1));
            }
        }
        sort(all(ver[i]),[&](pvt l, pvt r){
            return l.first.imag() < r.first.imag();
        });
    }
    // enumerate y corresponding middle x = (x1 + x2) / 2, each consecutive x1, x2
    vector<vector<vec>> mid(ms-1);
    rep(i,0,ms-1){
        ld mx = (vs[i].first.real() + vs[i+1].first.real()) / 2;
        line l({vec(mx,0),vec(mx,1)});
        rep(j,0,ns){
            for (auto p : cross_point(cirs[j],l)){
                mid[i].emplace_back(p);
            }
        }
        sort(all(mid[i]),[&](vec l, vec r){
            return l.imag() < r.imag();
        });
    }
    // enumerate point which is representing each area
    rep(itr,0,ms-1){
        int id = 0;
        rep(i,0,ver[itr].size()){
            if (ver[itr][i].second == 1) continue;
            if (ver[itr][i].second == -1){
                id++;
                continue;
            }
            rep(j,0,abs(ver[itr][i].second-1)){
                pnt.emplace_back((mid[itr][id]+mid[itr][id+1])/ld(2));
                id++;
            }
            id++;
        }
    }
    int psiz = pnt.size();
    vector<ll> pmsk(psiz,0);
    rep(j,0,psiz){
        rep(i,0,m){
            ld d1 = abs(a[es[i].first]-a[es[i].second]);
            ld d2 = abs(a[es[i].first]-pnt[j]);
            if (d2 < d1) pmsk[j] |= (1LL<<i);
        } //cout << pmsk[j] << endl; cout << pnt[j] << endl;
    }
    sort(all(pmsk)); pmsk.erase(unique(all(pmsk)),pmsk.end()); psiz = pmsk.size();
    map<ll,ld> indist, outdist;
    auto get_indist = [&](ll msk){
        if (msk == 0) return ld(0);
        if (indist.find(msk) != indist.end()) return indist[msk];
        vec rui(0,0);
        ld wgt = 0;
        rep(i,0,m){
            if (msk >> i & 1){
                rui += a[es[i].first] * vrs[i];
                wgt += vrs[i];
            }
        }
        rui /= wgt;
        ld res = 0;
        rep(i,0,m){
            if (msk >> i & 1){
                res += norm(rui-a[es[i].first]) * vrs[i];
            }
        }
        return indist[msk] = res;
    };
    auto get_outdist = [&](ll msk){
        if (msk == 0) return ld(0);
        if (outdist.find(msk) != outdist.end()) return outdist[msk];
        ld res = 0;
        rep(i,0,m){
            if (msk >> i & 1){
                res += norm(a[es[i].first]-a[es[i].second]) * vrs[i];
            }
        }
        return outdist[msk] = res;
    };
    auto calc = [&](ll msk){
        ld res = 2e18;
        rep(j,0,psiz){
            ll inmsk = pmsk[j]&msk;
            ll outmsk = inmsk^msk;
            chmin(res,get_indist(inmsk)+get_outdist(outmsk));
        }
        return res;
    };
    ld ans = 2e18;
    for (auto l : lines){
        vector<int> idc;
        ll lmsk = 0, rmsk = 0;
        rep(i,0,n){
            if (on_line(l,a[i])){
                idc.emplace_back(i);
                continue;
            }
            (sgn(cross(l.b-l.a,a[i]-l.a)) == 1 ? lmsk : rmsk) |= nmsk[i];
        }
        sort(all(idc),[&](int i, int j){
            return a[i].real() < a[j].real();
        });
        int siz = idc.size();
        vector<ll> lui(siz+1,0), rui(siz+1,0);
        rep(i,0,siz){
            lui[i+1] = (lui[i] | nmsk[idc[i]]);
        }
        rrep(i,0,siz){
            rui[i] = (rui[i+1] | nmsk[idc[i]]);
        }
        for (int cl = 0; cl <= siz; cl++){
            chmin(ans,calc(lmsk|lui[cl])+calc(rmsk|rui[cl]));
            chmin(ans,calc(rmsk|lui[cl])+calc(lmsk|rui[cl]));
        }
    }
    cout << sqrt(ans/m) << endl;
}

int main(){
    while (true){
        int n, m; cin >> n >> m;
        if (n == 0) break;
        solve1(n,m);
    }
}
accuracy: 1
time_ms: 3070
memory_kb: 18792
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using uint = unsigned int;
using ull = unsigned long long;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep1(i,n) for(int i=1;i<=int(n);i++)
#define per(i,n) for(int i=int(n)-1;i>=0;i--)
#define per1(i,n) for(int i=int(n);i>0;i--)
#define all(c) c.begin(),c.end()
#define si(x) int(x.size())
#define pb push_back
#define eb emplace_back
#define fs first
#define sc second
template<class T> using V = vector<T>;
template<class T> using VV = vector<vector<T>>;
template<class T,class U> bool chmax(T& x, U y){
	if(x<y){ x=y; return true; }
	return false;
}
template<class T,class U> bool chmin(T& x, U y){
	if(y<x){ x=y; return true; }
	return false;
}
template<class T> void mkuni(V<T>& v){sort(all(v));v.erase(unique(all(v)),v.end());}
template<class T> int lwb(const V<T>& v, const T& a){return lower_bound(all(v),a) - v.begin();}
template<class T>
V<T> Vec(size_t a) {
    return V<T>(a);
}
template<class T, class... Ts>
auto Vec(size_t a, Ts... ts) {
  return V<decltype(Vec<T>(ts...))>(a, Vec<T>(ts...));
}
template<class S,class T> ostream& operator<<(ostream& o,const pair<S,T> &p){
	return o<<"("<<p.fs<<","<<p.sc<<")";
}
template<class T> ostream& operator<<(ostream& o,const vector<T> &vc){
	o<<"{";
	for(const T& v:vc) o<<v<<",";
	o<<"}";
	return o;
}
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n-1); }

#ifdef LOCAL
#define show(x) cerr << "LINE" << __LINE__ << " : " << #x << " = " << (x) << endl
void dmpr(ostream& os){os<<endl;}
template<class T,class... Args>
void dmpr(ostream&os,const T&t,const Args&... args){
	os<<t<<" ~ ";
	dmpr(os,args...);
}
#define shows(...) cerr << "LINE" << __LINE__ << " : ";dmpr(cerr,##__VA_ARGS__)
#define dump(x) cerr << "LINE" << __LINE__ << " : " << #x << " = {";  \
	for(auto v: x) cerr << v << ","; cerr << "}" << endl;
#else
#define show(x) void(0)
#define dump(x) void(0)
#define shows(...) void(0)
#endif

template<class D> D divFloor(D a, D b){
	return a / b - (((a ^ b) < 0 && a % b != 0) ? 1 : 0);
}
template<class D> D divCeil(D a, D b) {
	return a / b + (((a ^ b) > 0 && a % b != 0) ? 1 : 0);
}

using D = double;
using P = complex<D>;
using L = pair<P,P>;
using Pol = vector<P>;
struct C{P p;D r;};
D inf=1e50,eps=1e-10,PI=acos(0.0)*2;
bool eq(D a, D b) { return abs(a-b)<eps;}
bool eq(P a, P b) { return abs(a-b)<eps;}
int sig(D a) { return eq(a,0) ? 0 : (a>0 ? 1 : -1);}
int large(D a,D b){return eq(a,b)?0:(a>b?1:-1);}
bool compxy (const P& l, const P& r){
	return eq(l.real(),r.real()) ? l.imag()<r.imag() : l.real() < r.real();
}
bool compyx (const P& l, const P& r){
	return eq(l.imag(),r.imag()) ? l.real()<r.real() : l.imag() < r.imag();
}
inline D dot(P a, P b) { return real(conj(a)*b);}
inline D cro(P a, P b) { return imag(conj(a)*b);}
//enum ENCCW{CCW(left)=1, CW(right)=-1, FRONT=-2, BACK=2, ON=0};
//ON優先(including endpoint)
inline int ccw (P a, P b, P c){
	if(sig(cro(b-a,c-a))==1) return 1;
	if(sig(cro(b-a,c-a))==-1) return -1;
	if(eq(abs(a-c)+abs(c-b),abs(a-b))) return 0;
	if(eq(abs(a-b)+abs(b-c),abs(a-c))) return -2;
	if(eq(abs(c-a)+abs(a-b),abs(c-b))) return 2;
	assert(false);
}
inline int ccw(L a,P p){return ccw(a.fs,a.sc,p);}
inline P proj(P a, P b){		//ベクトルaのbへの射影
	return (dot(a,b)/norm(b))*b;
}
inline D verlen(L l,P p){	//垂線の長さ(符号付き ccw(左)が正)
	return cro(l.sc-l.fs,p-l.fs)/abs(l.sc-l.fs);
}
inline P perp(L l, P p){		//垂線の足
	D t=dot(p-l.fs,l.fs-l.sc)/norm(l.fs-l.sc);
	return l.fs+t*(l.fs-l.sc);
}
inline P refl(L l, P p){
	return p+2.0*(perp(l,p)-p);
}
inline bool ispal(L a, L b){
	return sig(cro(a.fs-a.sc,b.fs-b.sc))==0;
}
inline bool ovLL(L a, L b){
	return ispal(a,b) && sig(cro(a.fs-a.sc,b.fs-a.sc))==0;
}
inline bool iLL(L a, L b){		//intersect or overload
	return !ispal(a,b) || ovLL(a,b);
}
inline bool iLS(L l, L s){		//intersect(including endpoint) or overload
	return cro(l.sc-l.fs,s.fs-l.fs)*cro(l.sc-l.fs,s.sc-l.fs)<eps;
}
inline bool iLSex(L l, L s){		//intersect(excluding endpoint)
	return cro(l.sc-l.fs,s.fs-l.fs)*cro(l.sc-l.fs,s.sc-l.fs)<-eps;
}
inline bool iLP(L l, P p){		//on line
	return abs(sig(cro(l.sc-p,l.fs-p)))!=1;
}
inline bool iSS(L a, L b){		//intersect(including endpoint) or overload
	return ccw(a.fs,a.sc,b.fs)*ccw(a.fs,a.sc,b.sc)<=0 && ccw(b.fs,b.sc,a.fs)*ccw(b.fs,b.sc,a.sc)<=0;
}
inline bool iSSex(L a, L b){		//intersect(excluding endpoint)
	return ccw(a.fs,a.sc,b.fs)*ccw(a.fs,a.sc,b.sc)<0 && ccw(b.fs,b.sc,a.fs)*ccw(b.fs,b.sc,a.sc)<0;
}
inline bool iSP(L s, P p){		//intersect(including endpoint) or overload
	return ccw(s.fs,s.sc,p)==0;
}
inline D dLP(L l, P p) { return abs(perp(l,p)-p);}
inline D dLL(L a, L b) { return iLL(a,b) ? 0 : dLP(a,b.fs);}
inline D dLS(L l, L s) { return iLS(l,s) ? 0 : min(dLP(l,s.fs),dLP(l,s.sc));}
inline D dSP(L s, P p) {
	P q=perp(s,p);
	return iSP(s,q) ? abs(p-q) : min(abs(p-s.fs),abs(p-s.sc));
}
inline D dSS(L a, L b) {
	if(iSS(a,b)) return 0;
	return min(min(dSP(a,b.fs),dSP(a,b.sc)),min(dSP(b,a.fs),dSP(b,a.sc)));
}
inline P intLL(L a, L b) {	//intersection
	assert(!ispal(a,b));
	D t=cro(a.sc-a.fs,a.sc-b.fs)/cro(a.sc-a.fs,b.sc-b.fs);
	return b.fs+t*(b.sc-b.fs);
}
//
inline int iCL(C c, L l){		//num of intersection(s)
	D d=dLP(l,c.p);
	return eq(d,c.r) ? 1 : (d<c.r ? 2 : 0);
}
bool containCC(C a,C b){	//a contain b? (edge case is true)
	return abs(a.p-b.p)+b.r<a.r+eps;
}
bool containCCex(C a,C b){	//a contain b? (edge case is false)
	return abs(a.p-b.p)+b.r<a.r-eps;
}
// 交点が2個のとき、aをbが削ると思うと、削れた部分はret[0] -> res[1] (ccw) の部分
vector<P> intCC(C a,C b){
	if(abs(a.p-b.p) > a.r+b.r + eps) return {};
	if(containCCex(a,b) || containCCex(b,a)) return {};
	D d = abs(a.p-b.p);
	D tmp = (a.r*a.r+d*d-b.r*b.r)/(2.0*a.r*d);
	if(tmp < -1) tmp = -1;
	if(tmp > 1) tmp = 1;
	D theta = acos(tmp);
	P p1 = a.p+(b.p-a.p)/d*polar(a.r,-theta);
	P p2 = a.p+(b.p-a.p)/d*polar(a.r,theta);
	if(eq(p1,p2)) return {p1};
	return {p1,p2};
}
inline vector<L> tanCP(C c,P p){
	int x=large(c.r,abs(p-c.p));
	vector<L> ret;
	if(x==1) return ret;
	if(x==0){
		ret.pb(L(p,p+(c.p-p)*P(0,1)));
		return ret;
	}
	D theta=acos(c.r/abs(p-c.p));
	ret.pb(L(p,c.p+(p-c.p)/abs(p-c.p)*polar(c.r,theta)));
	ret.pb(L(p,c.p+(p-c.p)/abs(p-c.p)*polar(c.r,-theta)));
	return ret;
}
inline Pol intCL(C c,L l){
	int x=large(dLP(l,c.p),c.r);
	Pol ret;
	if(x==1) return ret;
	if(x==0){
		ret.pb(perp(l,c.p));
		return ret;
	}
	D d=dLP(l,c.p);
	if(d<eps){
		ret.pb(c.p+(l.fs-l.sc)/abs(l.fs-l.sc)*c.r);
		ret.pb(c.p-(l.fs-l.sc)/abs(l.fs-l.sc)*c.r);
		return ret;
	}
	D theta=acos(d/c.r);
	P p=perp(l,c.p);
	ret.pb(c.p+(p-c.p)/d*polar(c.r,theta));
	ret.pb(c.p+(p-c.p)/d*polar(c.r,-theta));
	return ret;
}
inline vector<L> intan(C a,C b){
	P p=(a.r*b.p+b.r*a.p)/(a.r+b.r);
	return tanCP(a,p);
}
inline vector<L> outtan(C a,C b){
	if(a.r==b.r){
		vector<L> ret;
		P p=(a.p-b.p)/abs(a.p-b.p)*polar(a.r,PI/2);
		ret.pb(L(a.p+p,b.p+p));
		ret.pb(L(a.p-p,b.p-p));
		return ret;
	}
	P p=(a.r*b.p-b.r*a.p)/(a.r-b.r);
	return tanCP(a,p);
}
D aTri(P a, P b, P c){ return cro(b-a,c-a)/2;}
D aPol(Pol p){			//点集合はCCWに与える
	int n=p.size();
	D ret=0;
	rep(i,n) ret+=cro(p[i],p[(i+1)%n])/2;
	return ret;
}
P gPol(Pol p){			//多角形内部が一様な重さを持つときの重心
	int n=p.size();
	P g;
	D s=aPol(p);
	assert(s>eps);
	rep(i,n){
		D ds=cro(p[i],p[(i+1)%n])/2;
		g+=ds/3*(p[i]+p[(i+1)%n]);
	}
	return g/s;
}
//enum ENCONT{INP=1,ONP=0,OUTP=-1};
int contain(Pol pol, P p){
	bool in=false;
	rep(i,pol.size()){
		P a=pol[i]-p,b=pol[(i+1)%pol.size()]-p;
		if(ccw(a,b,P(0,0))==0) return 0;
		if(imag(a)>imag(b)) swap(a,b);
		if(sig(imag(a))<=0 && 0<sig(imag(b)) && ccw(P(0,0),a,b)==1) in=!in;
	}
	return in ? 1 : -1;
}
L BL;
bool compBL(const P& a,const P& b){			//BL上の点をソート(BL.fs側が小さい)
	return dot(BL.sc-BL.fs,a-BL.fs)<dot(BL.sc-BL.fs,b-BL.fs);
}
bool containE(Pol pol,L l){			//polは閉集合だと思って.
	vector<P> ps;
	ps.pb(l.fs);
	ps.pb(l.sc);
	int N=pol.size();
	rep(i,N){
		L a(pol[i],pol[(i+1)%N]);
		if(ispal(a,l)) continue;
		if(!ispal(a,l)&&iSS(a,l)) ps.pb(intLL(a,l));
	}
	BL=l;
	sort(all(ps),compBL);
	int K=ps.size();
	rep(i,K-1) ps.pb((ps[i]+ps[i+1])/2.0);
	for(P p:ps) if(!contain(pol,p)) return 0;
	return 1;
}
inline D heron(D a, D b, D c){
	double s=(a+b+c)/2;
	if(s-a<eps || s-b<eps || s-c<eps) return 0;		//S=0 || 三角形できない
	return sqrt(s*(s-a)*(s-b)*(s-c));
}
inline Pol conv(Pol p){		//convex
	int n=p.size(),k=0;
	sort(all(p),compxy);
	Pol ret(2*n);
	rep(i,n){
		while(k>=2 && ccw(ret[k-2],ret[k-1],p[i])<=0) --k;
		ret[k++]=p[i];
	}
	for(int i=n-2,t=k+1;i>=0;i--){
		while(k>=t && ccw(ret[k-2],ret[k-1],p[i])<=0) --k;
		ret[k++]=p[i];
	}
	ret.resize(k-1);
	return ret;
}
inline Pol convall(Pol p){		//conv上の点全部		//点が2回以上出てくる
	int n=p.size(),k=0;
	sort(all(p),compxy);
	Pol ret(2*n);
	rep(i,n){
		while(k>=2 && ccw(ret[k-2],ret[k-1],p[i])==-1) --k;
		ret[k++]=p[i];
	}
	for(int i=n-2,t=k+1;i>=0;i--){
		while(k>=t && ccw(ret[k-2],ret[k-1],p[i])==-1) --k;
		ret[k++]=p[i];
	}
	ret.resize(k-1);
	ret.erase(unique(all(ret)),ret.end());
	return ret;
}
inline Pol convexcut(Pol p,L l){	//ccw,leftが残る
	Pol ret;
	rep(i,p.size()){
		if(ccw(l.fs,l.sc,p[i])!=-1) ret.pb(p[i]);
		L s=L(p[i],p[(i+1)%p.size()]);
		if(iLSex(l,s)) ret.pb(intLL(l,s));
	}
	return ret;
}
inline Pol interpol(Pol a,Pol b){	//ccw,ccw
	rep(j,b.size()){
		a=convexcut(a,L(b[j],b[(j+1)%b.size()]));
	}
	return a;
}
inline vector<Pol> makevoronoi(Pol vp,Pol pol){	//left
	vector<Pol> ret;
	Pol polc=pol;
	rep(i,vp.size()){
		pol=polc;
		rep(j,vp.size()){
			if(i==j) continue;
			P p=(vp[i]+vp[j])/2.0,q=p+(vp[j]-vp[i])*P(0,1);
			pol=convexcut(pol,L(p,q));
		}
		ret.pb(pol);
	}
	return ret;
}
inline D pol_diameter(Pol p){
	p=conv(p);
	int n=p.size();
	assert(n>=2);
	if(n==2) return abs(p[0]-p[1]);
	int i=0,j=0;
	rep(k,n){
		if(!compxy(p[i],p[k])) i=k;
		if(compxy(p[j],p[k])) j=k;
	}
	D ret=0;
	int si=i,sj=j;
	while(i!=sj || j!=si){
		ret=max(ret,abs(p[i]-p[j]));
		if(cro(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j])<0) i=(i+1)%n;
		else j=(j+1)%n;
	}
	return ret;
}
inline D closest_pair(P *a, int n){
	if(n<=1) return inf;
	int m=n/2;
	D x=a[m].real();
	D d=min(closest_pair(a,m),closest_pair(a+m,n-m));
	inplace_merge(a,a+m,a+n,compyx);
	vector<P> b;
	rep(i,n){
		if(abs(x-a[i].real())>=d) continue;
		rep(j,b.size()){
			P dp=a[i]-b[b.size()-1-j];
			if(dp.imag()>=d) break;
			d=min(d,abs(dp));
		}
		b.pb(a[i]);
	}
	return d;
}
inline D compute_shortest(P *a,int n){
	sort(a,a+n,compxy);
	return closest_pair(a,n);
}

double rnd(double l,double r){
	static random_device rd;
	static mt19937 gen(rd());
	return uniform_real_distribution<double>(l,r)(gen);
}

// return {p \cap halfplane}
// size = O(N^2)
// time complexity: O(N^3) slow
// bit表現で持ってるので大きい時はvectorに変えようね！
// 無駄なのが含まれてるかもしれねえ　自信なし
// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1614
V<ll> enumeratePlaneDivision(V<P> p){
	int N = si(p);
	V<ll> divs;
//	rep(i,1<<N) divs.pb(i);
	divs.pb(0); divs.pb((1LL<<N)-1);
	rep(i,N) rep(j,N) if(i != j){
		P mid = (p[j]+p[i])/2.0;
		P vec = (p[j]-p[i]) * polar(1.0,1e-8);
		ll s=0, t=0;
		rep(k,N){
			if(cro(vec,p[k]-mid) < 0) s |= 1LL<<k;
			else t |= 1LL<<k;
		}
		divs.pb(s); divs.pb(t);
	}
	mkuni(divs);
	return divs;
}

// return { {i s.t. p \in c[i]} | p: point }
// 円の集合が与えられるので、どのような領域に分けられるか　というのを、円に含まれるか含まれないかの集合で特徴づけて計算する
// max: N^2-N+2
// とか言ったけどやや嘘で、正の面積をもつ領域しか列挙してない気もするし、あと無駄なのも含まれてる気もする
// ロバストにやりたくね～ これで許してくれ
// 各領域に対して、境界に交点を含まない場合→境界は円なので内と外をためす
// 含む場合、交点と2つの円弧に挟まれた部分を列挙すればよい
// と思うじゃん、bがaに内接してたら、a-bの部分は、交点の近傍からは得られないんだよね
// よく考えると、このように内接してるやつを避けるには、（他の交点からも得られない i.e. どこでも内接 ということを考慮すると、)
// ↑で言った円の内側を試すときにランダムな回転をして一点取れば良いことが示せる
// かしこいね～～～ もう一切このライブラリの事信用していません


V<ll> enumerateCircleInclusion(V<C> c){
	int N = si(c);
	V<ll> inclusions;
//	rep(i,1<<N) inclusions.pb(i);
	V<P> cands;
	D eps_here = 1e-8;
	rep(i,N){
		cands.pb(c[i].p + polar(c[i].r-eps_here, 1.0));
		cands.pb(c[i].p + polar(c[i].r+eps_here, 1.0));
	}
	rep(i,N) rep(j,N) if(i!=j){
		V<P> f = intCC(c[i],c[j]);
		for(P p: f){
			P d1 = (p-c[i].p); d1 /= abs(d1);
			P d2 = (p-c[j].p); d2 /= abs(d2);
			P dir = (d1+d2); dir /= abs(dir);
			rep(_,4){
				cands.pb(p + dir * eps_here);
				dir *= P(0,1);
			}
		}
	}
	for(P p: cands){
		ll s = 0;
		rep(i,N) if(abs(p-c[i].p) < c[i].r) s |= 1LL<<i;
		inclusions.pb(s);
	}
	mkuni(inclusions);
	return inclusions;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);		//DON'T USE scanf/printf/puts !!
	cout << fixed << setprecision(20);

	while(true){
		int N,M; cin >> N >> M;
		if(N == 0) break;
		V<P> p(N);
		rep(i,N){
			D x,y; cin >> x >> y;
			p[i] = P(x,y);
		}
		V<int> from(M),to(M);
		V<D> weight(M);
		rep(i,M){
			D v;
			cin >> from[i] >> to[i] >> v;
			from[i]--,to[i]--;
			weight[i] = 1.0/v/v;
		}
		V<C> c(M);
		rep(i,M) c[i] = {p[from[i]], abs(p[from[i]]-p[to[i]])};
		auto divs = enumeratePlaneDivision(p);		// N^2
		auto inc = enumerateCircleInclusion(c);		// M^2
		show(divs);show(inc);
		D ans = inf;
		for(ll sl: divs){
			auto f = [&](ll s){
				D res = inf;
				for(ll usecolor: inc){
					P red;
					D rr=0;
					rep(i,M) if(s&1LL<<from[i]){
						if(usecolor&1LL<<i){
							rr += weight[i];
							red += p[from[i]] * weight[i];
						}
					}
					if(rr) red /= rr;
					D tmp = 0;
					rep(i,M) if(s&1LL<<from[i]){
						if(usecolor&1LL<<i){
							tmp += weight[i] * norm(red - p[from[i]]);
						}else{	// black
							tmp += weight[i] * norm(p[to[i]] - p[from[i]]);
						}
					}
					chmin(res,tmp);
				}
				return res;
			};
			ll sr = ((1LL<<N)-1) ^ sl;
			chmin(ans,f(sl) + f(sr));
		}
		cout << sqrt(ans/M) << endl;
	}
}
accuracy: 1
time_ms: 1640
memory_kb: 4472
final_rank: 4

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;


#define EPS 0.00000001
#define SIZE 41

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

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

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

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};

struct Info{
	int from,to;
	double V,D,rev_V2;
};

struct DATA{
	DATA(Point arg_p,double arg_rad){
		p = arg_p;
		rad = arg_rad;
	}
	DATA(){
		rad = 0;
	}
	bool operator<(const struct DATA &arg) const{

		return rad < arg.rad;
	}
	Point p;
	double rad;
};


struct Circle{
	Point center;
	double r;
};

ll POW[SIZE];
int N,M,table[SIZE];
vector<int> STATE;
vector<int> INFO[SIZE];
double dp[1024*1024];
double DIST[SIZE],NUM = 100000;
Point point[SIZE];
Info info[SIZE];
Circle C[SIZE];
bool check[SIZE];
vector<DATA> ON_P[SIZE];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

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

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

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

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

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;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
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(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

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

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

//円と円の交点
vector<Point> getCrossPoints(Circle c1,Circle c2){

	vector<Point> res;

	double d = abs(c1.center-c2.center);
	double a = acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
	double t = arg(c2.center-c1.center);

	res.push_back(Point(c1.center+polar(c1.r,t+a)));
	res.push_back(Point(c1.center+polar(c1.r,t-a)));

	return res;
}

//t^2を求める
double getT(Point a,Point b,double V){

	double A = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
	return A/(V*V);
}

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	STATE.clear();

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

		INFO[i].clear();
		DIST[i] = 0;
		ON_P[i].clear();
	}

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

		scanf("%lf %lf",&point[i].x,&point[i].y);
	}

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

		scanf("%d %d %lf",&info[i].from,&info[i].to,&info[i].V);
		info[i].from--;
		info[i].to--;

		info[i].rev_V2 = 1.0/(info[i].V*info[i].V);
		double tmp_dist = calc_dist(point[info[i].from],point[info[i].to]);
		info[i].D = tmp_dist*tmp_dist;

		C[i].center = point[info[i].from];
		C[i].r = tmp_dist;

		INFO[info[i].from].push_back(i);

		DIST[i] = getT(point[info[i].from],point[info[i].to],info[i].V);
	}

	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){

			Point mid_p = (point[i]+point[k])/2;

			Line base_line;

			if(fabs(point[i].x-point[k].x) < EPS){

				base_line = Line(Point(-NUM,mid_p.y),Point(NUM,mid_p.y));

			}else if(fabs(point[i].y-point[k].y) < EPS){

				base_line = Line(Point(mid_p.x,-NUM),Point(mid_p.x,NUM));

			}else{

				double tmp_slope = calc_slope(Line(point[i],point[k]));
				tmp_slope = (-1.0)/tmp_slope;

				base_line = Line(Point(mid_p.x-NUM,mid_p.y-NUM*tmp_slope),Point(mid_p.x+NUM,mid_p.y+NUM*tmp_slope));
			}

			vector<int> I,K,MID;
			I.push_back(i);
			K.push_back(k);

			for(int a = 0; a < N; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(base_line,point[a]) < EPS){

					MID.push_back(a);
				}else{

					Line work_line = Line(point[a],point[i]);
					if(is_Cross(base_line,work_line)){

						K.push_back(a);

					}else{

						I.push_back(a);
					}
				}
			}

			int state_I = 0,state_K = 0;
			for(int a = 0; a < I.size(); a++){

				state_I += POW[I[a]];
			}
			for(int a = 0; a < K.size(); a++){

				state_K += POW[K[a]];
			}

			if(MID.size() == 0){

				STATE.push_back(state_I);
				STATE.push_back(state_K);
				continue;
			}

			for(int state = 0; state < POW[MID.size()]; state++){
				int work_I = state_I;
				int work_K = state_K;
				for(int loop = 0; loop < MID.size(); loop++){
					if(state&POW[loop]){

						work_I += POW[MID[loop]];

					}else{

						work_K += POW[MID[loop]];

					}
				}

				STATE.push_back(work_I);
				STATE.push_back(work_K);
			}
		}
	}

	sort(STATE.begin(),STATE.end());
	STATE.erase(unique(STATE.begin(),STATE.end()),STATE.end());


	for(int i = 0; i < M-1; i++){
		for(int k = i+1; k < M; k++){

			double tmp_dist = calc_dist(C[i].center,C[k].center);

			if(tmp_dist > C[i].r+C[k].r+EPS)continue;
			if(min(C[i].r,C[k].r)+tmp_dist+EPS < max(C[i].r,C[k].r)){

				continue;
			}

			vector<Point> ret = getCrossPoints(C[i],C[k]);
			for(int a = 0; a < ret.size(); a++){

				ON_P[i].push_back(DATA(ret[a],calc_rad(ret[a]-C[i].center)));
				ON_P[k].push_back(DATA(ret[a],calc_rad(ret[a]-C[k].center)));
			}
		}
	}

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

		ON_P[i].push_back(DATA(Point(C[i].center.x+C[i].r,C[i].center.y),0));
		ON_P[i].push_back(DATA(Point(C[i].center.x,C[i].center.y+C[i].r),M_PI/2));
		ON_P[i].push_back(DATA(Point(C[i].center.x-C[i].r,C[i].center.y),M_PI));
		ON_P[i].push_back(DATA(Point(C[i].center.x,C[i].center.y-C[i].r),(M_PI*3)/2.0));
	}

	for(int i = 0; i < M; i++){
		if(ON_P[i].size() == 0)continue;

		sort(ON_P[i].begin(),ON_P[i].end());
	}


	vector<ll> cross_STATE;

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

		vector<Point> ret;
		ret.push_back(C[i].center);

		for(int k = 0; k < ON_P[i].size(); k++){

			Point tmp_p = ON_P[i][k].p;

			int size = ON_P[i].size();
			double tmp_rad = ON_P[i][(k+1)%size].rad-ON_P[i][k].rad;
			if((k+1) == size){

				tmp_rad += 2*M_PI;
			}
			tmp_rad /= 2;

			Point calc_P = rotate(C[i].center,tmp_p,tmp_rad);

			Vector tmp_vec = calc_P-C[i].center;
			tmp_vec = tmp_vec/abs(tmp_vec);

			ret.push_back(calc_P+tmp_vec*10*EPS);
			ret.push_back(calc_P-tmp_vec*10*EPS);
		}


		for(int a = 0; a < ret.size(); a++){

			ll tmp_S = 0;

			for(int b = 0; b < M; b++){
				double tmp_dist = calc_dist(C[b].center,ret[a]);
				if(tmp_dist > C[b].r+EPS)continue;

				tmp_S += POW[b];
			}
			cross_STATE.push_back(tmp_S);
		}
	}

	sort(cross_STATE.begin(),cross_STATE.end());
	cross_STATE.erase(unique(cross_STATE.begin(),cross_STATE.end()),cross_STATE.end());


	dp[0] = 0;
	for(int state = 1; state < POW[N]; state++){

		dp[state] = HUGE_NUM;
	}

	for(int i = 0; i < STATE.size(); i++){

		int base_state = STATE[i];

		vector<int> BIN;
		int count = 0;

		ll MASK = 0;

		for(int k = 0; k < N; k++){
			if(base_state&POW[k]){
				for(int a = 0; a < INFO[k].size(); a++){

					BIN.push_back(INFO[k][a]);
					MASK += POW[INFO[k][a]];
				}
			}
		}

		set<ll> SET;

		for(int a = 0; a < BIN.size(); a++){

			SET.insert(POW[BIN[a]]);
		}
		for(int a = 0; a < cross_STATE.size(); a++){

			SET.insert(MASK&cross_STATE[a]);
		}

		for(auto tmp_S: SET){

			double sum = 0;

			vector<int> warp_vec;

			for(int k = 0; k < BIN.size(); k++){
				if(tmp_S&POW[BIN[k]]){

					warp_vec.push_back(BIN[k]);

				}else{

					sum += DIST[BIN[k]];
				}
			}

			double X = 0,Y = 0;

			for(int E = 0; E < 2; E++){

				double bunshi = 0;
				double bunbo = 0;

				for(int b = 0; b < warp_vec.size(); b++){

					int tmp_from = info[warp_vec[b]].from;

					if(E == 0){

						bunshi += point[tmp_from].x*info[warp_vec[b]].rev_V2;

					}else{

						bunshi += point[tmp_from].y*info[warp_vec[b]].rev_V2;
					}
					bunbo += info[warp_vec[b]].rev_V2;
				}

				if(E == 0){

					X = bunshi/bunbo;
				}else{

					Y = bunshi/bunbo;
				}
			}

			Point WARP_P = Point(X,Y);
			for(int b = 0; b < warp_vec.size(); b++){
				if(tmp_S&POW[warp_vec[b]]){
					sum += getT(point[info[warp_vec[b]].from],WARP_P,info[warp_vec[b]].V);
				}
			}

			dp[base_state] = min(dp[base_state],sum);
		}

	}

	double ans = HUGE_NUM;

	for(int state = 0; state < POW[N]; state++){

		ans = min(ans,dp[state]+dp[(POW[N]-1)-state]);
	}

	printf("%.12lf\n",sqrt(ans/M));
}

int main(){

	POW[0] = 1;
	for(int i = 1; i < SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	while(true){

		scanf("%d %d",&N,&M);
		if(N == 0 && M == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 4300
memory_kb: 16056
final_rank: 9

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;


#define EPS 0.00000001
#define SIZE 41

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

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

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

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};

struct Info{
	int from,to;
	double V,D,rev_V2;
};

struct DATA{
	DATA(Point arg_p,double arg_rad){
		p = arg_p;
		rad = arg_rad;
	}
	DATA(){
		rad = 0;
	}
	bool operator<(const struct DATA &arg) const{

		return rad < arg.rad;
	}
	Point p;
	double rad;
};


struct Circle{
	Point center;
	double r;
};

ll POW[SIZE];
int N,M,table[SIZE];
vector<int> STATE;
vector<int> INFO[SIZE];
double MULT = 10;
double dp[1024*1024],diff_x[3] = {-MULT*EPS,0,MULT*EPS},diff_y[3] = {-MULT*EPS,0,MULT*EPS};
double DIST[SIZE],NUM = 100000;
Point point[SIZE];
Info info[SIZE];
Circle C[SIZE];
bool check[SIZE];
vector<DATA> ON_P[SIZE];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

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

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

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

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

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;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
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(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

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

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

//円と円の交点
vector<Point> getCrossPoints(Circle c1,Circle c2){

	vector<Point> res;

	double d = abs(c1.center-c2.center);
	double a = acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
	double t = arg(c2.center-c1.center);

	res.push_back(Point(c1.center+polar(c1.r,t+a)));
	res.push_back(Point(c1.center+polar(c1.r,t-a)));

	return res;
}

//t^2を求める
double getT(Point a,Point b,double V){

	double A = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
	return A/(V*V);
}

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	STATE.clear();

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

		INFO[i].clear();
		DIST[i] = 0;
		ON_P[i].clear();
	}

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

		scanf("%lf %lf",&point[i].x,&point[i].y);
	}

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

		scanf("%d %d %lf",&info[i].from,&info[i].to,&info[i].V);
		info[i].from--;
		info[i].to--;

		info[i].rev_V2 = 1.0/(info[i].V*info[i].V);
		double tmp_dist = calc_dist(point[info[i].from],point[info[i].to]);
		info[i].D = tmp_dist*tmp_dist;

		C[i].center = point[info[i].from];
		C[i].r = tmp_dist;

		INFO[info[i].from].push_back(i);

		DIST[i] = getT(point[info[i].from],point[info[i].to],info[i].V);
	}

	/*2空港間の垂直二等分線を使い、空港の集合を二分割して、
	  同じワープポイントを使う可能性のある集合を全列挙する
	  (垂直二等分線上に空港が並ぶ場合あり)
	  同じ空港に属する別の便が、異なるワープポイントを使うことはない
	  使うなら近いほうがいいから。ただし、目的地の方が近ければ、ワープポイントを使わない
	  */
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){

			Point mid_p = (point[i]+point[k])/2;

			Line base_line; //垂直二等分線

			if(fabs(point[i].x-point[k].x) < EPS){ //垂直

				base_line = Line(Point(-NUM,mid_p.y),Point(NUM,mid_p.y));

			}else if(fabs(point[i].y-point[k].y) < EPS){ //水平

				base_line = Line(Point(mid_p.x,-NUM),Point(mid_p.x,NUM));

			}else{

				double tmp_slope = calc_slope(Line(point[i],point[k]));
				tmp_slope = (-1.0)/tmp_slope;

				base_line = Line(Point(mid_p.x-NUM,mid_p.y-NUM*tmp_slope),Point(mid_p.x+NUM,mid_p.y+NUM*tmp_slope));
			}

			vector<int> I,K,MID;
			I.push_back(i);
			K.push_back(k);

			for(int a = 0; a < N; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(base_line,point[a]) < EPS){ //垂直二等分線上にある空港

					MID.push_back(a);
				}else{

					Line work_line = Line(point[a],point[i]); //iへの直線
					if(is_Cross(base_line,work_line)){

						K.push_back(a);

					}else{

						I.push_back(a);
					}
				}
			}

			int state_I = 0,state_K = 0;
			for(int a = 0; a < I.size(); a++){

				state_I += POW[I[a]];
			}
			for(int a = 0; a < K.size(); a++){

				state_K += POW[K[a]];
			}

			if(MID.size() == 0){

				STATE.push_back(state_I);
				STATE.push_back(state_K);
				continue;
			}

			//垂直二等分線上の空港を、IまたはKに振り分ける
			for(int state = 0; state < POW[MID.size()]; state++){
				int work_I = state_I;
				int work_K = state_K;
				for(int loop = 0; loop < MID.size(); loop++){
					if(state&POW[loop]){

						work_I += POW[MID[loop]];

					}else{

						work_K += POW[MID[loop]];

					}
				}

				STATE.push_back(work_I);
				STATE.push_back(work_K);
			}
		}
	}

	sort(STATE.begin(),STATE.end());
	STATE.erase(unique(STATE.begin(),STATE.end()),STATE.end());


	//円弧上の点の回転角度を計算するため、ある円上にある交点を計算
	for(int i = 0; i < M-1; i++){
		for(int k = i+1; k < M; k++){

			//交差しない
			double tmp_dist = calc_dist(C[i].center,C[k].center);

			//片方がもう片方を含む
			if(tmp_dist > C[i].r+C[k].r+EPS)continue;
			if(min(C[i].r,C[k].r)+tmp_dist+EPS < max(C[i].r,C[k].r)){

				continue;
			}

			vector<Point> ret = getCrossPoints(C[i],C[k]);
			for(int a = 0; a < ret.size(); a++){

				ON_P[i].push_back(DATA(ret[a],calc_rad(ret[a]-C[i].center)));
				ON_P[k].push_back(DATA(ret[a],calc_rad(ret[a]-C[k].center)));
			}
		}
	}

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

		ON_P[i].push_back(DATA(Point(C[i].center.x+C[i].r,C[i].center.y),0));
		ON_P[i].push_back(DATA(Point(C[i].center.x,C[i].center.y+C[i].r),M_PI/2));
		ON_P[i].push_back(DATA(Point(C[i].center.x-C[i].r,C[i].center.y),M_PI));
		ON_P[i].push_back(DATA(Point(C[i].center.x,C[i].center.y-C[i].r),(M_PI*3)/2.0));
	}

	for(int i = 0; i < M; i++){
		if(ON_P[i].size() == 0)continue;

		sort(ON_P[i].begin(),ON_P[i].end());
	}


	vector<ll> cross_STATE;

	//ある2円を交差させた際に、その共通領域を同じ共通領域とする便の集合を前計算
	for(int i = 0; i < M; i++){

		vector<Point> ret;
		ret.push_back(C[i].center);

		for(int k = 0; k < ON_P[i].size(); k++){

			Point tmp_p = ON_P[i][k].p;

			int size = ON_P[i].size();
			double tmp_rad = ON_P[i][(k+1)%size].rad-ON_P[i][k].rad;
			if((k+1) == size){

				tmp_rad += 2*M_PI;
			}
			tmp_rad /= 2;

			Point calc_P = rotate(C[i].center,tmp_p,tmp_rad);

			Vector tmp_vec = calc_P-C[i].center;
			tmp_vec = tmp_vec/abs(tmp_vec);

			ret.push_back(calc_P+tmp_vec*10*EPS);
			ret.push_back(calc_P-tmp_vec*10*EPS);

			/*//誤差が出るので、適当に近傍の点を入れる
			for(int e = 0; e < 3; e++){
				for(int f = 0; f < 3; f++){

					Point adj_p = Point(calc_P.x+diff_x[e],calc_P.y+diff_y[f]);

					if(calc_dist(C[i].center,adj_p) > C[i].r+EPS || calc_dist(C[k].center,adj_p) > C[k].r+EPS)continue;

					ret.push_back(adj_p);
				}
			}

			calc_P = rotate(C[i].center,tmp_p,-tmp_rad);


			//誤差が出るので、適当に近傍の点を入れる
			for(int e = 0; e < 3; e++){
				for(int f = 0; f < 3; f++){

					Point adj_p = Point(calc_P.x+diff_x[e],calc_P.y+diff_y[f]);

					if(calc_dist(C[i].center,adj_p) > C[i].r+EPS || calc_dist(C[k].center,adj_p) > C[k].r+EPS)continue;

					ret.push_back(adj_p);
				}
			}

*/
		}


		for(int a = 0; a < ret.size(); a++){

			ll tmp_S = 0;

			for(int b = 0; b < M; b++){
				double tmp_dist = calc_dist(C[b].center,ret[a]);
				if(tmp_dist > C[b].r+EPS)continue;

				tmp_S += POW[b];
			}
			cross_STATE.push_back(tmp_S);
		}
	}

	sort(cross_STATE.begin(),cross_STATE.end());
	cross_STATE.erase(unique(cross_STATE.begin(),cross_STATE.end()),cross_STATE.end());

	/*for(int a = 0; a < cross_STATE.size(); a++){

		printf("%lld\n",cross_STATE[a]);
	}

	return;*/


	dp[0] = 0; //空集合
	for(int state = 1; state < POW[N]; state++){

		dp[state] = HUGE_NUM;
	}


	//ある状態について、ワープを使う空港と使わない空港の組み合わせを全探索する
	for(int i = 0; i < STATE.size(); i++){

		int base_state = STATE[i]; //空港の集合
		//printf("\nbase_state:%d\n",base_state);

		for(int k = 0; k < M; k++){

			check[k] = false;
			table[k] = -1;
		}

		vector<int> BIN; //便のindex
		int count = 0;

		ll MASK = 0;

		for(int k = 0; k < N; k++){
			if(base_state&POW[k]){
				for(int a = 0; a < INFO[k].size(); a++){

					BIN.push_back(INFO[k][a]);
					check[INFO[k][a]] = true;
					table[INFO[k][a]] = count++; //この集合での、便のindex
					MASK += POW[INFO[k][a]];
				}
			}
		}

		set<ll> SET; //ワープ地点を使う便の集合

		for(int a = 0; a < BIN.size(); a++){

			SET.insert(POW[BIN[a]]);
		}
		for(int a = 0; a < cross_STATE.size(); a++){

			SET.insert(MASK&cross_STATE[a]);
		}

		/*for(int a = 0; a < BIN.size()-1; a++){
			for(int b = a+1; b < BIN.size(); b++){

				SET.insert(MASK&ADJ[BIN[a]][BIN[b]]);
			}
		}*/

		for(auto tmp_S: SET){

			double sum = 0;

			vector<int> warp_vec;

			for(int k = 0; k < BIN.size(); k++){
				if(tmp_S&POW[BIN[k]]){ //ワープを使う

					warp_vec.push_back(BIN[k]);

				}else{

					sum += DIST[BIN[k]];
				}
			}

			double X = 0,Y = 0;

			for(int E = 0; E < 2; E++){

				double bunshi = 0;
				double bunbo = 0;

				for(int b = 0; b < warp_vec.size(); b++){

					int tmp_from = info[warp_vec[b]].from;

					if(E == 0){

						bunshi += point[tmp_from].x*info[warp_vec[b]].rev_V2;

					}else{

						bunshi += point[tmp_from].y*info[warp_vec[b]].rev_V2;
					}
					bunbo += info[warp_vec[b]].rev_V2;
				}

				if(E == 0){

					X = bunshi/bunbo;
				}else{

					Y = bunshi/bunbo;
				}
			}

			Point WARP_P = Point(X,Y); //ワープ地点
			for(int b = 0; b < warp_vec.size(); b++){
				if(tmp_S&POW[warp_vec[b]]){
					sum += getT(point[info[warp_vec[b]].from],WARP_P,info[warp_vec[b]].V);
				}
			}

			dp[base_state] = min(dp[base_state],sum);
		}

	}

	double ans = HUGE_NUM;

	for(int state = 0; state < POW[N]; state++){

		ans = min(ans,dp[state]+dp[(POW[N]-1)-state]);
	}

	printf("%.12lf\n",sqrt(ans/M));
}

int main(){

	POW[0] = 1;
	for(int i = 1; i < SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	while(true){

		scanf("%d %d",&N,&M);
		if(N == 0 && M == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 4280
memory_kb: 16128
final_rank: 10

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};
struct C{
    P p;
    double r;
    C(const P& p, const double& r) : p(p), r(r) {}
    C(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}
P unit(const P &p){
    return p/abs(p);
}
P rotate(const P &p, double rad){
    return p *P(cos(rad), sin(rad));
}

VP crosspointCC(C a, C b){
    VP ret;
    if(a.p == b.p && a.r == b.r){
        return ret;
    }
    if(a.r < b.r) swap(a,b);
    double dist = abs(b.p-a.p);
    P dir = a.r*unit(b.p-a.p);
    if(EQ(dist, a.r+b.r) || EQ(dist, a.r-b.r)){
        ret.push_back(a.p +dir);
    }else if(a.r-b.r < dist && dist < a.r+b.r){
        double cos = (a.r*a.r +dist*dist -b.r*b.r)/(2*a.r*dist);
        double sin = sqrt(1 -cos*cos);
        ret.push_back(a.p +dir*P(cos, sin));
        ret.push_back(a.p +dir*P(cos, -sin));
    }
    return ret;
}

struct edge{
    int from,to;
    double v;
    edge(int f, int t, double v):from(f),to(t),v(v){}
    edge(){};
};

vector<int> linear_division(const VP &p){
    int n = p.size();
    vector<int> ret;
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            int div = 0;
            vector<pair<P, int> > online;
            for(int k=0; k<n; k++){
                if(ccw(p[i], p[j], p[k]) == 1){
                    div |= 1<<k;
                }else if(ccw(p[i], p[j], p[k]) != -1){
                    online.emplace_back(p[k], k);
                }
            }
            sort(online.begin(), online.end());
            for(int d=0; d<2; d++){
                for(int k=0; k<(int)online.size(); k++){
                    div ^= 1<<online[k].second;
                    if((div & 1) == 0){
                        ret.push_back(div ^ ((1<<n) -1));
                    }else{
                        ret.push_back(div);
                    }
                }
            }
        }
    }
    sort(ret.begin(), ret.end());
    ret.erase(unique(ret.begin(), ret.end()), ret.end());
    return ret;
}

vector<long long int> circle_division(const VP &p, const vector<edge> &e){
    int m = e.size();
    vector<C> c(m);
    for(int i=0; i<m; i++){
        c[i] = C(p[e[i].from], abs(p[e[i].from] -p[e[i].to]));
    }
    vector<vector<double> > cpa(m);
    for(int i=0; i<m; i++){
        for(int j=0; j<m; j++){
            VP cp = crosspointCC(c[i], c[j]);
            for(const P &point: cp){
                cpa[i].push_back(arg(point -c[i].p));
            }
        }
        cpa[i].push_back(-PI);
        cpa[i].push_back(PI);
        sort(cpa[i].begin(), cpa[i].end());
    }

    VP cand;
    for(int i=0; i<m; i++){
        for(int j=0; j<(int)cpa[i].size()-1; j++){
            double angle = (cpa[i][j] +cpa[i][j+1]) /2;
            P rot = rotate(P(c[i].r, 0), angle);
            cand.push_back(c[i].p +rot +unit(rot)*EPS*10.0);
            cand.push_back(c[i].p +rot -unit(rot)*EPS*10.0);
        }
    }

    vector<long long int> ret;
    for(const P &point: cand){
        long long int div = 0;
        for(int i=0; i<m; i++){
            if(abs(point -c[i].p) < c[i].r +EPS){
                div |= 1LL<<i;
            }
        }
        ret.push_back(div);
    }
    sort(ret.begin(), ret.end());
    ret.erase(unique(ret.begin(), ret.end()), ret.end());
    return ret;
}

double solve_onewarp(const VP &p, const vector<edge> &e, long long int ldiv, const vector<long long int> &cdiv){
    int m = e.size();
    double ret = INF;
    for(long long int inout: cdiv){
        double weight = 0;
        P g(0, 0);
        for(int i=0; i<m; i++){
            if((1<<e[i].from & ldiv) == 0) continue;
            if((1LL<<i & inout) != 0){
                double w = 1/e[i].v /e[i].v;
                g += w *p[e[i].from];
                weight += w;
            }
        }
        g /= weight;
        double sub = 0;
        for(int i=0; i<m; i++){
            if((1<<e[i].from & ldiv) == 0) continue;
            if((1LL<<i & inout) != 0){
                sub += norm((p[e[i].from] -g) /e[i].v);
            }else{
                sub += norm((p[e[i].from] -p[e[i].to]) /e[i].v);
            }
        }
        ret = min(ret, sub);
    }
    return ret;
}

double solve_twowarp(const VP &p, const vector<edge> &e){
    vector<int> ldiv = linear_division(p);
    vector<long long int> cdiv = circle_division(p, e);
    double ret = INF;
    for(int bit: ldiv){
        int revbit = bit ^((1<<p.size()) -1);
        ret = min(ret, solve_onewarp(p, e, bit, cdiv) +solve_onewarp(p, e, revbit, cdiv));
    }
    return sqrt(ret /e.size());
}

int main(){
    while(1){
        int n,m;
        cin >> n >> m;
        if(n==0) break;

        VP p(n);
        for(int i=0; i<n; i++){
            double x,y;
            cin >> x >> y;
            p[i] = P(x, y);
        }
        vector<edge> e(m);
        for(int i=0; i<m; i++){
            cin >> e[i].from >> e[i].to >> e[i].v;
            e[i].from--; e[i].to--;
        }
        cout << fixed << setprecision(10);
        cout << solve_twowarp(p, e) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1490
memory_kb: 3964
final_rank: 3

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};
struct C{
    P p;
    double r;
    C(const P& p, const double& r) : p(p), r(r) {}
    C(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}
P unit(const P &p){
    return p/abs(p);
}
P rotate(const P &p, double rad){
    return p *P(cos(rad), sin(rad));
}

VP crosspointCC(C a, C b){
    VP ret;
    if(a.p == b.p && a.r == b.r){
        return ret;
    }
    if(a.r < b.r) swap(a,b);
    double dist = abs(b.p-a.p);
    P dir = a.r*unit(b.p-a.p);
    if(EQ(dist, a.r+b.r) || EQ(dist, a.r-b.r)){
        ret.push_back(a.p +dir);
    }else if(a.r-b.r < dist && dist < a.r+b.r){
        double cos = (a.r*a.r +dist*dist -b.r*b.r)/(2*a.r*dist);
        double sin = sqrt(1 -cos*cos);
        ret.push_back(a.p +dir*P(cos, sin));
        ret.push_back(a.p +dir*P(cos, -sin));
    }
    return ret;
}

struct edge{
    int from,to;
    double v;
    edge(int f, int t, double v):from(f),to(t),v(v){}
    edge(){};
};

vector<int> linear_division(const VP &p){
    int n = p.size();
    vector<int> ret;
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            int ccwbit = 0;
            vector<pair<P, int> > online;
            for(int k=0; k<n; k++){
                if(ccw(p[i], p[j], p[k]) == 1){
                    ccwbit |= 1<<k;
                }else if(ccw(p[i], p[j], p[k]) != -1){
                    online.emplace_back(p[k], k);
                }
            }
            sort(online.begin(), online.end());
            for(int d=0; d<2; d++){
                for(int k=0; k<(int)online.size(); k++){
                    ccwbit ^= 1<<online[k].second;
                    if((ccwbit & 1) == 0){
                        ret.push_back(ccwbit ^ ((1<<n) -1));
                    }else{
                        ret.push_back(ccwbit);
                    }
                }
            }
        }
    }
    sort(ret.begin(), ret.end());
    ret.erase(unique(ret.begin(), ret.end()), ret.end());
    return ret;
}

double solve_onewarp(const VP &p, const vector<edge> &e){
    int m = e.size();
    if(m == 0) return 0.0;

    vector<C> c(m);
    for(int i=0; i<m; i++){
        c[i] = C(p[e[i].from], abs(p[e[i].from] -p[e[i].to]));
    }
    vector<vector<double> > cpa(m);
    for(int i=0; i<m; i++){
        for(int j=0; j<m; j++){
            VP cp = crosspointCC(c[i], c[j]);
            for(const P &point: cp){
                cpa[i].push_back(arg(point -c[i].p));
            }
        }
        cpa[i].push_back(-PI);
        cpa[i].push_back(PI);
        sort(cpa[i].begin(), cpa[i].end());
    }

    VP cand;
    for(int i=0; i<m; i++){
        for(int j=0; j<(int)cpa[i].size()-1; j++){
            double angle = (cpa[i][j] +cpa[i][j+1]) /2;
            P rot = rotate(P(c[i].r, 0), angle);
            cand.push_back(c[i].p +rot +unit(rot)*EPS*10.0);
            cand.push_back(c[i].p +rot -unit(rot)*EPS*10.0);
        }
    }

    double ret = INF;
    for(const P &point: cand){
        long long int inout = 0;
        double weight = 0;
        P g(0, 0);
        for(int i=0; i<m; i++){
            if(abs(point -c[i].p) < c[i].r +EPS){
                double w = 1/e[i].v /e[i].v;
                g += w *c[i].p;
                inout |= 1LL<<i;
                weight += w;
            }
        }
        g /= weight;
        double sub = 0;
        for(int i=0; i<m; i++){
            if((1LL<<i & inout) != 0){
                sub += norm((p[e[i].from] -g) /e[i].v);
            }else{
                sub += norm((p[e[i].from] -p[e[i].to]) /e[i].v);
            }
        }
        ret = min(ret, sub);
    }
    return ret;
}

double solve_twowarp(const VP &p, const vector<edge> &e){
    vector<int> division = linear_division(p);
    double ret = INF;
    for(int bit: division){
        vector<vector<edge> > newe(2);
        for(const edge &ed: e){
            newe[(1<<ed.from & bit) != 0].push_back(ed);
        }
        ret = min(ret, solve_onewarp(p, newe[0]) +solve_onewarp(p, newe[1]));
    }
    return sqrt(ret /e.size());
}

int main(){
    while(1){
        int n,m;
        cin >> n >> m;
        if(n==0) break;

        VP p(n);
        for(int i=0; i<n; i++){
            double x,y;
            cin >> x >> y;
            p[i] = P(x, y);
        }
        vector<edge> e(m);
        for(int i=0; i<m; i++){
            cin >> e[i].from >> e[i].to >> e[i].v;
            e[i].from--; e[i].to--;
        }
        cout << fixed << setprecision(10);
        cout << solve_twowarp(p, e) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 5670
memory_kb: 3816
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}

const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

class Point{
public:
  double x, y;

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

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

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

class Circle{
public:
	Point c;
	double r;
};
typedef Point Vector;

double dot(Vector a, Vector b){
	return a.x*b.x + a.y*b.y;
}
double cross(Vector a, Vector b){
	return a.x*b.y - a.y*b.x;
}
Point rotate(Point p,double angle){
  return Point(p.x*cos(angle) - p.y*sin(angle),
			   p.x*sin(angle) + p.y*cos(angle));
}

pair<Point, Point> getCrossPoints(const Circle& c1, const Circle& c2){
  double d = (c2.c - c1.c).abs();
  double a = (c1.r*c1.r + d*d - c2.r*c2.r) / (2*d);
  Vector e = (c2.c - c1.c) / d;
  Vector h = rotate(e, PI/2) * sqrt(max(c1.r*c1.r - a*a, 0.));
  if(d + min(c1.r, c2.r) <= max(c1.r, c2.r))
	return MP(c1.c + e*c1.r, c1.c + e*c1.r);

  return MP(c1.c + e*a + h, c1.c + e*a - h);
}

// ??????????????§?????¢???????????????
// ?????????????????°???O(N^2)
void partCircles(const vector<Circle>& cs, set<LL>& res){
  int N = SZ(cs);
  vector<Point> ps;
  REP(i,N) REP(j,N){
	if(i == j) continue;
	auto cc = getCrossPoints(cs[i], cs[j]);
	Point crossPoints[2] = {cc.FF, cc.SS};
	REP(k,2){
	  Vector delta = crossPoints[1-k] - crossPoints[k];
	  if(delta.abs() == 0)
		delta = crossPoints[k] - cs[i].c;
	  delta /= delta.abs();
	  REP(d,4){
		ps.PB(crossPoints[k] + delta*EPS);
		delta = rotate(delta, PI/2);
	  }
	}
  }

  for(auto&& p: ps){
	LL bit = 0;
	REP(i,N)
	  if((cs[i].c - p).abs() < cs[i].r)
		bit |= 1LL<<i;
	res.insert(bit);
  }
}

// ?????¢?????´?????§??????????????¨????????????????????????????????????
// ????????????O(N^2)
void partPoints(vector<Point> ps, set<PLL>& res){
  int N = SZ(ps);
  REP(i,N){
	Vector e(0,1);
	REP(d,4){
	  ps.PB(ps[i]+e*EPS);
	  e = rotate(e, PI/2);
	}
  }
  
  REP(i,SZ(ps)) REP(j,SZ(ps)){
	if(i == j) continue;
	Point p1 = ps[i];
	Point p2 = ps[j];
	Vector e = p2 - p1;
	e /= e.abs();
	e = rotate(e, PI/2);
	LL b1 = 0, b2 = 0;
	REP(k,N)
	  if(dot(e, ps[k]-p1) >= 0)
		b1 |= 1LL<<k;
	  else
		b2 |= 1LL<<k;
	if(b1 > b2) swap(b1, b2);
	res.insert(MP(b1,b2));
  }
}

int N, M;
double calcBest(LL bps, LL bcs, VI& as, vector<double>& vs, vector<Circle>& cs){
  Point q(0, 0);
  double inv = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	double tmp = 1. / (vs[i] * vs[i]);
	q.x += cs[i].c.x * tmp;
	q.y += cs[i].c.y * tmp;
	inv += tmp;
  }
  if(inv <= 0) return 0;
  q.x /= inv;
  q.y /= inv;

  double res = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	res += ((cs[i].c - q).norm() - (cs[i].r * cs[i].r)) / (vs[i] * vs[i]);
  }
  return res;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  while(cin>>N>>M,N){
	vector<Point> ps(N);
	REP(i,N) cin >> ps[i].x >> ps[i].y;
	VI as(M), bs(M);
	vector<double> vs(M);
	vector<Circle> cs(M);
	REP(i,M){
	  cin >> as[i] >> bs[i] >> vs[i];
	  --as[i];
	  --bs[i];
	  cs[i].c = ps[as[i]];
	  cs[i].r = (ps[bs[i]] - ps[as[i]]).abs();
	}
	if(M <= 2){
	  cout << fixed << setprecision(9) << 0. << endl;
	  continue;
	}

	set<LL> planes;
	set<PLL> points;
	partCircles(cs, planes);
	partPoints(ps, points);

	double best = 0.;
	for(auto&& bpos: points){
	  double d1 = 0, d2 = 0;
	  for(auto&& bpls: planes){
		mini(d1, calcBest(bpos.FF, bpls, as, vs, cs));
		mini(d2, calcBest(bpos.SS, bpls, as, vs, cs));
	  }
	  mini(best, d1+d2);
	}

	double ans = 0;
	REP(i,M) ans += pow(cs[i].r / vs[i], 2);
	cout << fixed << setprecision(9) << sqrt((ans+best)/M) << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 780
memory_kb: 3928
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
 
using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;
 
#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
 
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)
 
#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}
 
const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;
 
class Point{
public:
  double x, y;
 
  Point(double x = 0.0, double y = 0.0) : x(x), y(y){}
 
  Point operator + (const Point& p) const{ return Point(x + p.x, y + p.y); }
  Point& operator += (const Point& p){ x += p.x; y += p.y; return *this;}
  Point operator - (const Point& p) const{ return Point(x - p.x, y - p.y); }
  Point& operator -= (const Point& p){ x -= p.x; y -= p.y; return *this;}
  Point operator * (double a) const{ return Point(a*x, a*y); }
  Point& operator *= (double a){ x *= a; y *= a; return *this;}
  Point operator / (double a) const{ return Point(x / a, y / a); }
  Point& operator /= (double a){ x /= a; y /= a; return *this;}
 
  double abs(){ return sqrt(norm()); }
  double norm(){ return x*x + y*y; }
};
 
class Circle{
public:
    Point c;
    double r;
};
typedef Point Vector;
 
double dot(Vector a, Vector b){
    return a.x*b.x + a.y*b.y;
}
double cross(Vector a, Vector b){
    return a.x*b.y - a.y*b.x;
}
Point rotate(Point p,double angle){
  return Point(p.x*cos(angle) - p.y*sin(angle),
               p.x*sin(angle) + p.y*cos(angle));
}
 
pair<Point, Point> getCrossPoints(const Circle& c1, const Circle& c2){
  double d = (c2.c - c1.c).abs();
  double a = (c1.r*c1.r + d*d - c2.r*c2.r) / (2*d);
  Vector e = (c2.c - c1.c) / d;
  Vector h = rotate(e, PI/2) * sqrt(max(c1.r*c1.r - a*a, 0.));

  return MP(c1.c + e*a + h, c1.c + e*a - h);
}

void partCircles(const vector<Circle>& cs, set<LL>& res){
  int N = SZ(cs);
  vector<Point> ps;
  REP(i,N) REP(j,N){
    if(i == j) continue;
    auto cc = getCrossPoints(cs[i], cs[j]);
    Point crossPoints[2] = {cc.FF, cc.SS};
    REP(k,2){
      Vector delta = crossPoints[1-k] - crossPoints[k];
      if(delta.abs() == 0)
        delta = crossPoints[k] - cs[i].c;
      delta /= delta.abs();
      REP(d,4){
        ps.PB(crossPoints[k] + delta*EPS);
        delta = rotate(delta, PI/2);
      }
    }
  }
 
  for(auto&& p: ps){
    LL bit = 0;
    REP(i,N)
      if((cs[i].c - p).abs() < cs[i].r)
        bit |= 1LL<<i;
    res.insert(bit);
  }
}
 

void partPoints(vector<Point> ps, set<PLL>& res){
  int N = SZ(ps);
  REP(i,N){
    Vector e(0,1);
    REP(d,4){
      ps.PB(ps[i]+e*EPS);
      e = rotate(e, PI/2);
    }
  }
   
  REP(i,SZ(ps)) REP(j,SZ(ps)){
    if(i == j) continue;
    Point p1 = ps[i];
    Point p2 = ps[j];
    Vector e = p2 - p1;
    e /= e.abs();
    e = rotate(e, PI/2);
    LL b1 = 0, b2 = 0;
    REP(k,N)
      if(dot(e, ps[k]-p1) >= 0)
        b1 |= 1LL<<k;
      else
        b2 |= 1LL<<k;
    if(b1 > b2) swap(b1, b2);
    res.insert(MP(b1,b2));
  }
}
 
int N, M;
double calcBest(LL bps, LL bcs, VI& as, vector<double>& vs, vector<Circle>& cs){
  Point q(0, 0);
  double inv = 0.;
  REP(i,M){
    if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
    double tmp = 1. / (vs[i] * vs[i]);
    q.x += cs[i].c.x * tmp;
    q.y += cs[i].c.y * tmp;
    inv += tmp;
  }
  if(inv <= 0) return 0;
  q.x /= inv;
  q.y /= inv;
 
  double res = 0.;
  REP(i,M){
    if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
    res += ((cs[i].c - q).norm() - (cs[i].r * cs[i].r)) / (vs[i] * vs[i]);
  }
  return res;
}
 
int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);
 
  while(cin>>N>>M,N){
    vector<Point> ps(N);
    REP(i,N) cin >> ps[i].x >> ps[i].y;
    VI as(M), bs(M);
    vector<double> vs(M);
    vector<Circle> cs(M);
    REP(i,M){
      cin >> as[i] >> bs[i] >> vs[i];
      --as[i];
      --bs[i];
      cs[i].c = ps[as[i]];
      cs[i].r = (ps[bs[i]] - ps[as[i]]).abs();
    }
    if(M <= 2){
      cout << fixed << setprecision(9) << 0. << endl;
      continue;
    }
 
    set<LL> planes;
    set<PLL> points;
    partCircles(cs, planes);
    partPoints(ps, points);
 
    double best = 0.;
    for(auto&& bpos: points){
      double d1 = 0, d2 = 0;
      for(auto&& bpls: planes){
        mini(d1, calcBest(bpos.FF, bpls, as, vs, cs));
        mini(d2, calcBest(bpos.SS, bpls, as, vs, cs));
      }
      mini(best, d1+d2);
    }
 
    double ans = 0;
    REP(i,M) ans += pow(cs[i].r / vs[i], 2);
    cout << fixed << setprecision(9) << sqrt((ans+best)/M) << endl;
  }
 
  return 0;
}
accuracy: 1
time_ms: 770
memory_kb: 3968
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}

const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

class Point{
public:
  double x, y;

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

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

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

class Circle{
public:
	Point c;
	double r;
};
typedef Point Vector;

double dot(Vector a, Vector b){
	return a.x*b.x + a.y*b.y;
}
double cross(Vector a, Vector b){
	return a.x*b.y - a.y*b.x;
}
Point rotate(Point p,double angle){
  return Point(p.x*cos(angle) - p.y*sin(angle),
			   p.x*sin(angle) + p.y*cos(angle));
}

pair<Point, Point> getCrossPoints(const Circle& c1, const Circle& c2){
  double d = (c2.c - c1.c).abs();
  double a = (c1.r*c1.r + d*d - c2.r*c2.r) / (2*d);
  Vector e = (c2.c - c1.c) / d;
  Vector h = rotate(e, PI/2) * sqrt(max(c1.r*c1.r - a*a, 0.));
  if(d + min(c1.r, c2.r) <= max(c1.r, c2.r))
	return MP(c1.c + e*c1.r, c1.c + e*c1.r);

  return MP(c1.c + e*a + h, c1.c + e*a - h);
}

// ??????????????§?????¢???????????????
// ?????????????????°???O(N^2)
void partCircles(const vector<Circle>& cs, set<LL>& res){
  int N = SZ(cs);
  vector<Point> ps;
  REP(i,N) REP(j,N){
	if(i == j) continue;
	auto cc = getCrossPoints(cs[i], cs[j]);
	Point crossPoints[2] = {cc.FF, cc.SS};
	REP(k,2){
	  Vector delta = crossPoints[1-k] - crossPoints[k];
	  if(delta.abs() == 0)
		delta = crossPoints[k] - cs[i].c;
	  delta /= delta.abs();
	  REP(d,4){
		ps.PB(crossPoints[k] + delta*EPS);
		delta = rotate(delta, PI/2);
	  }
	}
  }

  for(auto&& p: ps){
	LL bit = 0;
	REP(i,N)
	  if((cs[i].c - p).abs() < cs[i].r)
		bit |= 1LL<<i;
	res.insert(bit);
  }
}

// ?????¢?????´?????§??????????????¨????????????????????????????????????
// ????????????O(N^2)
void partPoints(vector<Point> ps, set<PLL>& res){
  int N = SZ(ps);
  REP(i,N){
	Vector e(0,1);
	REP(d,4){
	  ps.PB(ps[i]+e*EPS);
	  e = rotate(e, PI/2);
	}
  }
  
  REP(i,SZ(ps)) REP(j,SZ(ps)){
	if(i == j) continue;
	Point p1 = ps[i];
	Point p2 = ps[j];
	Vector e = p2 - p1;
	e /= e.abs();
	e = rotate(e, PI/2);
	LL b1 = 0, b2 = 0;
	REP(k,N)
	  if(dot(e, ps[k]-p1) >= 0)
		b1 |= 1LL<<k;
	  else
		b2 |= 1LL<<k;
	if(b1 > b2) swap(b1, b2);
	res.insert(MP(b1,b2));
  }
}

int N, M;
double calcBest(LL bps, LL bcs, VI& as, vector<double>& vs, vector<Circle>& cs){
  Point q(0, 0);
  double inv = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	double tmp = 1. / (vs[i] * vs[i]);
	q.x += cs[i].c.x * tmp;
	q.y += cs[i].c.y * tmp;
	inv += tmp;
  }
  if(inv <= 0) return 0;
  q.x /= inv;
  q.y /= inv;

  double res = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	res += ((cs[i].c - q).norm() - (cs[i].r * cs[i].r)) / (vs[i] * vs[i]);
  }
  return res;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  while(cin>>N>>M,N){
	vector<Point> ps(N);
	REP(i,N) cin >> ps[i].x >> ps[i].y;
	VI as(M), bs(M);
	vector<double> vs(M);
	vector<Circle> cs(M);
	REP(i,M){
	  cin >> as[i] >> bs[i] >> vs[i];
	  --as[i];
	  --bs[i];
	  cs[i].c = ps[as[i]];
	  cs[i].r = (ps[bs[i]] - ps[as[i]]).abs();
	}

	set<LL> planes;
	set<PLL> points;
	partCircles(cs, planes);
	partPoints(ps, points);

	double best = 0.;
	for(auto&& bpos: points){
	  double d1 = 0, d2 = 0;
	  for(auto&& bpls: planes){
		mini(d1, calcBest(bpos.FF, bpls, as, vs, cs));
		mini(d2, calcBest(bpos.SS, bpls, as, vs, cs));
	  }
	  mini(best, d1+d2);
	}

	double ans = 0;
	REP(i,M) ans += pow(cs[i].r / vs[i], 2);
	cout << fixed << setprecision(9) << sqrt((ans+best)/M) << endl;
  }

  return 0;
}
accuracy: 0.5
time_ms: 840
memory_kb: 4024
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}

const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

class Point{
public:
  double x, y;

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

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

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

class Circle{
public:
	Point c;
	double r;
};
typedef Point Vector;

double dot(Vector a, Vector b){
	return a.x*b.x + a.y*b.y;
}
double cross(Vector a, Vector b){
	return a.x*b.y - a.y*b.x;
}
Point rotate(Point p,double angle){
  return Point(p.x*cos(angle) - p.y*sin(angle),
			   p.x*sin(angle) + p.y*cos(angle));
}

pair<Point, Point> getCrossPoints(const Circle& c1, const Circle& c2){
  double d = (c2.c - c1.c).abs();
  double a = (c1.r*c1.r + d*d - c2.r*c2.r) / (2*d);
  Vector e = (c2.c - c1.c) / d;
  Vector h = rotate(e, PI/2) * sqrt(max(c1.r*c1.r - a*a, 0.));
  return make_pair(c1.c + e*a + h, c1.c + e*a - h);
}

// ??????????????§?????¢???????????????
// ?????????????????°???O(N^2)
void partCircles(const vector<Circle>& cs, set<LL>& res){
  int N = SZ(cs);
  vector<Point> ps;
  REP(i,N) REP(j,N){
	if(i == j) continue;
	auto cc = getCrossPoints(cs[i], cs[j]);
	Point crossPoints[2] = {cc.FF, cc.SS};
	REP(k,2){
	  Vector delta = crossPoints[1-k] - crossPoints[k];
	  if(delta.abs() == 0) delta.x = 1;
	  delta /= delta.abs();
	  REP(d,4){
		ps.PB(crossPoints[k] + delta*EPS);
		delta = rotate(delta, PI/2);
	  }
	}
  }

  for(auto&& p: ps){
	LL bit = 0;
	REP(i,N)
	  if((cs[i].c - p).abs() < cs[i].r)
		bit |= 1LL<<i;
	res.insert(bit);
  }
}

// ?????¢?????´?????§??????????????¨????????????????????????????????????
// ????????????O(N^2)
void partPoints(vector<Point> ps, set<PLL>& res){
  int N = SZ(ps);
  REP(i,N){
	Vector e(0,1);
	REP(d,4){
	  ps.PB(ps[i]+e*EPS);
	  e = rotate(e, PI/2);
	}
  }
  
  REP(i,SZ(ps)) REP(j,SZ(ps)){
	if(i == j) continue;
	Point p1 = ps[i];
	Point p2 = ps[j];
	Vector e = p2 - p1;
	e /= e.abs();
	e = rotate(e, PI/2);
	LL b1 = 0, b2 = 0;
	REP(k,N)
	  if(dot(e, ps[k]-p1) >= 0)
		b1 |= 1LL<<k;
	  else
		b2 |= 1LL<<k;
	if(b1 > b2) swap(b1, b2);
	res.insert(MP(b1,b2));
  }
}

int N, M;
double calcBest(LL bps, LL bcs, VI& as, vector<double>& vs, vector<Circle>& cs){
  Point q(0, 0);
  double inv = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	double tmp = 1. / (vs[i] * vs[i]);
	q.x += cs[i].c.x * tmp;
	q.y += cs[i].c.y * tmp;
	inv += tmp;
  }
  if(inv <= 0) return 0;
  q.x /= inv;
  q.y /= inv;

  double res = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	res += ((cs[i].c - q).norm() - (cs[i].r * cs[i].r)) / (vs[i] * vs[i]);
  }
  return res;
}
Point calcBestQ(LL bps, LL bcs, VI& as, vector<double>& vs, vector<Circle>& cs){
  Point q(0, 0);
  double inv = 0.;
  REP(i,M){
	if((bcs>>i&1) == 0 || (bps>>as[i]&1) == 0) continue;
	double tmp = 1. / (vs[i] * vs[i]);
	q.x += cs[i].c.x * tmp;
	q.y += cs[i].c.y * tmp;
	inv += tmp;
  }
  if(inv <= 0) return 0;
  q.x /= inv;
  q.y /= inv;

  return q;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int ccc=0;
  while(cin>>N>>M,N){
	++ccc;
	vector<Point> ps(N);
	REP(i,N) cin >> ps[i].x >> ps[i].y;
	VI as(M), bs(M);
	vector<double> vs(M);
	vector<Circle> cs(M);
	REP(i,M){
	  cin >> as[i] >> bs[i] >> vs[i];
	  --as[i];
	  --bs[i];
	  cs[i].c = ps[as[i]];
	  cs[i].r = (ps[bs[i]] - ps[as[i]]).abs();
	}

	set<LL> planes;
	set<PLL> points;
	partCircles(cs, planes);
	partPoints(ps, points);

	double best = 0.;
	for(auto&& bpos: points){
	  double d1 = 0, d2 = 0;
	  for(auto&& bpls: planes){
		mini(d1, calcBest(bpos.FF, bpls, as, vs, cs));
		mini(d2, calcBest(bpos.SS, bpls, as, vs, cs));
	  }
	  mini(best, d1+d2);
	}

	double ans = 0;
	REP(i,M) ans += pow(cs[i].r / vs[i], 2);
	cout << fixed << setprecision(9) << sqrt((ans+best)/M) << endl;
  }

  return 0;
}
accuracy: 0.5
time_ms: 830
memory_kb: 4024
final_rank: 11