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

#include<unordered_map>

#include<unordered_set>

#pragma warning(disable:4996)

using namespace std;

using ld = long double;

template<class T>

using Table = vector<vector<T>>;

const ld eps=1e-9;



//// < "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\a.txt" > "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\b.answer"



typedef double Weight;



struct Edge {

	int src, dst;

	Weight weight;

	int id;

	Edge(int src_, int dst_, Weight weight_,const int id_) :

		src(src_), dst(dst_), weight(weight_),id(id_) { }

	Edge(int src, int dst, Weight weight) :

		src(src), dst(dst), weight(weight) { }

	Edge() :src(0), dst(0), weight(0) {



	}

};

const Weight INF = 1e18;

const Weight ZERO = 0;

bool operator < (const Edge &e, const Edge &f) {

	return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!

	e.src != f.src ? e.src < f.src : e.dst < f.dst;

}

typedef vector<Edge> Edges;

typedef vector<Edges> Graph;

ld getdis(const vector<ld>&f, const vector<ld>&t) {

	ld amin = -100;

	ld amax = 100;

	int n = 50;

	while (n--) {

		ld amid0 = (amin*2 + amax) /3;

		ld amid1 = (amin + amax * 2) / 3;

		ld len0 = 0;

		ld len1 = 0;

		{

		

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

				len0 += (t[i] - amid0*f[i])*(t[i] - amid0*f[i]);

			}

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

				len1 += (t[i] - amid1*f[i])*(t[i] - amid1*f[i]);

			}

		}

		if (len0<len1) {

			amax = amid1;

		}

		else {

			amin = amid0;

		}

		if (!n)return len0;

	}

}



namespace getcycle {

	vector<Edge>get_cycle(const Graph&g,const int start) {

		vector<Edge>prev_es(g.size());

		for (auto es : g) {

			for (auto e : es) {

				prev_es[e.dst] = e;

			}

		}

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

			if (i == start)continue;

			int now = i;

			vector<Edge>cycles;

			vector<int>comes(g.size(),-1);

			comes[now] = 0;

			int num = 1;

			while (1) {

				cycles.emplace_back(prev_es[now]);

				now = prev_es[now].src;

				if (comes[now]!=-1) {

					cycles = vector < Edge>(cycles.begin() + comes[now], cycles.end());

					reverse(cycles.begin(), cycles.end());

					return cycles;

				}

				else if (now == start) {

					break;

				}

				comes[now] = num++;

			}

		}

		return vector<Edge>(0);

	}

}



//aoj2309???varify??????????????£??????????????§????????????????????????

pair<Weight,Graph> chu_liu(const Graph&g, const int start,const int e_size) {



	vector<Edge>cycle_edges;

	ld total_len = 0;

	{

		Graph tree(g.size());

		{

			Graph revg(g.size());





			for (auto es : g) {

				for (auto e : es) {

					revg[e.dst].emplace_back(e.dst, e.src, e.weight);

				}

			}

			for (int node = 0; node < g.size(); ++node) {

				if (node == start)continue;

				else {

					Weight amin = INF;

					Edge min_edge;

					for (auto reve : revg[node]) {

						if (amin > reve.weight) {

							amin = reve.weight;

							min_edge = Edge(reve.dst, reve.src, reve.weight);

						}

					}

					if (amin < INF) {

						total_len += min_edge.weight;

						tree[min_edge.src].emplace_back(min_edge);

					}

				}

			}

		}

		cycle_edges = getcycle::get_cycle(tree, start);

	}

	

	if (cycle_edges.empty()) {

		return make_pair(total_len,g);

	}

	else {

		vector<bool>node_is_cycle(g.size());



		/*????´???°???Edge?????°????????§??????*/

		vector<int>edge_is_cycle(e_size);



		vector<Weight>prev_lens(g.size(), ZERO);

		

		for (auto ce : cycle_edges) {

			node_is_cycle[ce.src] = true;

			prev_lens[ce.dst] = ce.weight;

		}

		Graph newg(g.size());

		const int compress = cycle_edges[0].src;

		/*????´???°???Edge?????°????????§??????*/

		vector<Edge>memo(e_size);

		for (int s = 0; s < g.size();++s){

			bool src_is_cycle = node_is_cycle[s];

			for (auto e : g[s]) {

				memo[e.id] = e;

				bool dst_is_cycle = node_is_cycle[e.dst];

				if (src_is_cycle&&dst_is_cycle) {

					continue;

				}

				else if (src_is_cycle) {

					e.src = compress;

				}

				else if (dst_is_cycle) {

					e.weight -= prev_lens[e.dst];

					e.dst = compress;

				}

				newg[e.src].push_back(e);

			}

		}

		auto p=chu_liu(newg, start, e_size);

		Graph compress_tree(p.second);

		Graph ans_tree(g.size());

		for (auto es : compress_tree) {

			for (auto e : es) {

				const Edge prev_edge(memo[e.id]);

				ans_tree[prev_edge.src].emplace_back(prev_edge);

			}

		}

		Weight cycle_len = 0;

		for (auto e : cycle_edges) {

			cycle_len += e.weight;

		}

		return make_pair(p.first + cycle_len, ans_tree);

	}

}



int main() {

	int N, M; cin >> N >> M;

	vector<vector<ld>>vecs(M,vector<ld>(N));

	vector<vector<ld>>edges(M, vector<ld > (M));

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

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

			cin >> vecs[i][j];

		}

	}

	const int start = 0;

	const int node = 1;

	Graph g(M+1);

	int id = 0;

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

		ld inidis = 0;

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

			inidis += vecs[i][j] * vecs[i][j];

		}

		g[start].emplace_back(start, node + i, inidis,id++);

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

			if (i != j) {

				ld dis = getdis(vecs[i], vecs[j]);

				g[node + i].emplace_back(node + i, node + j, dis, id++);

			}

		}

	}

	auto p=chu_liu(g, start,(g.size())*((g.size()+1)));

	cout <<fixed<<setprecision(22)<< p.first << endl;

	return 0;

}

// Optimized solution to the same problem (faster):
#include "bits/stdc++.h"

#include<unordered_map>

#include<unordered_set>

#pragma warning(disable:4996)

using namespace std;

using ld = long double;

template<class T>

using Table = vector<vector<T>>;

const ld eps=1e-9;



//// < "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\a.txt" > "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\b.answer"



typedef double Weight;



struct Edge {

	int src, dst;

	Weight weight;

	int id;

	Edge(int src_, int dst_, Weight weight_,const int id_) :

		src(src_), dst(dst_), weight(weight_),id(id_) { }

	Edge(int src, int dst, Weight weight) :

		src(src), dst(dst), weight(weight) { }

	Edge() :src(0), dst(0), weight(0) {



	}

};

const Weight INF = 1e18;

const Weight ZERO = 0;

bool operator < (const Edge &e, const Edge &f) {

	return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!

	e.src != f.src ? e.src < f.src : e.dst < f.dst;

}

typedef vector<Edge> Edges;

typedef vector<Edges> Graph;

ld getdis(const vector<ld>&f, const vector<ld>&t) {

	ld amin = -100;

	ld amax = 100;

	int n = 30;

	while (n--) {

		ld amid0 = (amin*5 + amax*4) /9;

		ld amid1 = (amin*4 + amax * 5) / 9;

		ld len0 = 0;

		ld len1 = 0;

		{

		

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

				len0 += (t[i] - amid0*f[i])*(t[i] - amid0*f[i]);

			}

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

				len1 += (t[i] - amid1*f[i])*(t[i] - amid1*f[i]);

			}

		}

		if (len0<len1) {

			amax = amid1;

		}

		else {

			amin = amid0;

		}

		if (!n)return len0;

	}

}



namespace getcycle {

	vector<Edge>get_cycle(const Graph&g,const int start) {

		vector<Edge>prev_es(g.size());

		for (auto es : g) {

			for (auto e : es) {

				prev_es[e.dst] = e;

			}

		}

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

			if (i == start)continue;

			int now = i;

			vector<Edge>cycles;

			vector<int>comes(g.size(),-1);

			comes[now] = 0;

			int num = 1;

			while (1) {

				cycles.emplace_back(prev_es[now]);

				now = prev_es[now].src;

				if (comes[now]!=-1) {

					cycles = vector < Edge>(cycles.begin() + comes[now], cycles.end());

					reverse(cycles.begin(), cycles.end());

					return cycles;

				}

				else if (now == start) {

					break;

				}

				comes[now] = num++;

			}

		}

		return vector<Edge>(0);

	}

}



//aoj2309???varify??????????????£??????????????§????????????????????????

pair<Weight,Graph> chu_liu(const Graph&g, const int start,const int e_size) {



	vector<Edge>cycle_edges;

	ld total_len = 0;

	{

		Graph tree(g.size());

		{

			Graph revg(g.size());





			for (auto es : g) {

				for (auto e : es) {

					revg[e.dst].emplace_back(e.dst, e.src, e.weight);

				}

			}

			for (int node = 0; node < g.size(); ++node) {

				if (node == start)continue;

				else {

					Weight amin = INF;

					Edge min_edge;

					for (auto reve : revg[node]) {

						if (amin > reve.weight) {

							amin = reve.weight;

							min_edge = Edge(reve.dst, reve.src, reve.weight);

						}

					}

					if (amin < INF) {

						total_len += min_edge.weight;

						tree[min_edge.src].emplace_back(min_edge);

					}

				}

			}

		}

		cycle_edges = getcycle::get_cycle(tree, start);

	}

	

	if (cycle_edges.empty()) {

		return make_pair(total_len,g);

	}

	else {

		vector<bool>node_is_cycle(g.size());



		/*????´???°???Edge?????°????????§??????*/

		vector<int>edge_is_cycle(e_size);



		vector<Weight>prev_lens(g.size(), ZERO);

		

		for (auto ce : cycle_edges) {

			node_is_cycle[ce.src] = true;

			prev_lens[ce.dst] = ce.weight;

		}

		Graph newg(g.size());

		const int compress = cycle_edges[0].src;

		/*????´???°???Edge?????°????????§??????*/

		vector<Edge>memo(e_size);

		for (int s = 0; s < g.size();++s){

			bool src_is_cycle = node_is_cycle[s];

			for (auto e : g[s]) {

				memo[e.id] = e;

				bool dst_is_cycle = node_is_cycle[e.dst];

				if (src_is_cycle&&dst_is_cycle) {

					continue;

				}

				else if (src_is_cycle) {

					e.src = compress;

				}

				else if (dst_is_cycle) {

					e.weight -= prev_lens[e.dst];

					e.dst = compress;

				}

				newg[e.src].push_back(e);

			}

		}

		auto p=chu_liu(newg, start, e_size);

		Graph compress_tree(p.second);

		Graph ans_tree(g.size());

		for (auto es : compress_tree) {

			for (auto e : es) {

				const Edge prev_edge(memo[e.id]);

				ans_tree[prev_edge.src].emplace_back(prev_edge);

			}

		}

		Weight cycle_len = 0;

		for (auto e : cycle_edges) {

			cycle_len += e.weight;

		}

		return make_pair(p.first + cycle_len, ans_tree);

	}

}



int main() {

	int N, M; cin >> N >> M;

	vector<vector<ld>>vecs(M,vector<ld>(N));

	vector<vector<ld>>edges(M, vector<ld > (M));

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

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

			cin >> vecs[i][j];

		}

	}

	const int start = 0;

	const int node = 1;

	Graph g(M+1);

	int id = 0;

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

		ld inidis = 0;

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

			inidis += vecs[i][j] * vecs[i][j];

		}

		g[start].emplace_back(start, node + i, inidis,id++);

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

			if (i != j) {

				ld dis = getdis(vecs[i], vecs[j]);

				g[node + i].emplace_back(node + i, node + j, dis, id++);

			}

		}

	}

	auto p=chu_liu(g, start,(g.size())*((g.size()+1)));

	cout <<fixed<<setprecision(22)<< p.first << endl;

	return 0;

}

// Fastest known solution for this problem: