#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
 
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);
 
#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))
 
typedef double Weight;
struct Edge {
  int src;
  int dest;
  Weight weight;
  Edge(int src, int dest, Weight weight) : src(src), dest(dest), weight(weight) {;}
  bool operator<(const Edge &rhs) const {
    if (weight != rhs.weight) { return weight > rhs.weight; }
    if (src != rhs.src) { return src < rhs.src; }
    return dest < rhs.dest;
  }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;
 
void PrintMatrix(const Matrix &matrix) {
  for (int y = 0; y < (int)matrix.size(); y++) {
    for (int x = 0; x < (int)matrix[y].size(); x++) {
      printf("%.3f ", matrix[y][x]);
    }
    puts("");
  }
}
 
 
void SocDfs(const Graph &g, int from, vector<int> &visit, vector<int> &st) {
  visit[from] = 1;
  for (Edges::const_iterator it = g[from].begin(); it != g[from].end(); it++) {
    if (visit[it->dest]) { continue; }
    SocDfs(g, it->dest, visit, st);
  }
  st.push_back(from);
}
 
vector<vector<int> > Soc(const Graph &g) {
  const int n = g.size();
  vector<vector<int> > ret;
  Graph revg(n);
  for (int i = 0; i < n; i++) {
    for (Edges::const_iterator it = g[i].begin(); it != g[i].end(); it++) {
      revg[it->dest].push_back(Edge(it->dest, i, it->weight));
    }
  }
  vector<int> st;
  vector<int> visit(n, 0);
  for (int i = 0; i < n; i++) {
    if (visit[i]) { continue; }
    SocDfs(g, i, visit, st);
  }
  visit = vector<int>(n, 0);
  for (int i = n - 1; i >= 0; i--) {
    int index = st[i];
    if (visit[index]) { continue; }
    vector<int> nret;
    SocDfs(revg, index, visit, nret);
    ret.push_back(nret);
  }
  return ret;
}
 
// need Soc
Weight Arborescence(const Graph &g, int root) {
  const int n = g.size();
  Weight ret = 0;
  vector<Weight> inCost(n, 1000000000LL);
  vector<int> parent(n, -1);
  for (int from = 0; from < n; from++) {
    for (Edges::const_iterator it = g[from].begin(); it != g[from].end(); it++) {
      if (it->weight < inCost[it->dest]) {
        parent[it->dest] = from;
        inCost[it->dest] = it->weight;
      }
      inCost[it->dest] = min(inCost[it->dest], it->weight);
    }
  }
  Graph ng(n);
  for (int i = 0; i < n; i++) {
    if (i == root) { continue; }
    if (parent[i] == -1) { return 1000000000LL; }
    ng[parent[i]].push_back(Edge(parent[i], i, 0));
    ret += inCost[i];
  }
  vector<vector<int> > connect = Soc(ng);
  int m = connect.size();
  if (m == n) { return ret; }
  vector<int> mapto(n, -1);
  vector<int> cycle(n, 0);
  ret = 0;
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < (int)connect[i].size(); j++) {
      mapto[connect[i][j]] = i;
      if (connect[i].size() != 1) {
        cycle[connect[i][j]] = 1;
        ret += inCost[connect[i][j]];
      }
    }
  }
  ng = Graph(m);
  for (int from = 0; from < n; from++) {
    for (Edges::const_iterator it = g[from].begin(); it != g[from].end(); it++) {
      int to = it->dest;
      if (to == root || mapto[from] == mapto[to]) { continue; }
      Weight cost = it->weight;
      if (cycle[to]) {
        cost -= inCost[to];
      }
      ng[mapto[from]].push_back(Edge(mapto[from], mapto[to], cost));
    }
  }
  return min(1e+10, ret + Arborescence(ng, mapto[root]));
  //return min(1000000000LL, ret + Arborescence(ng, mapto[root]));
}
 
double vect[110][110];
int n, m;
 
inline double square(double x) { return x * x; }
 
double Len(int x) {
  double ret = 0.0;
  REP(i, n) { ret += square(vect[x][i]); }
  return ret;
}
double Inner(int i, int j) {
  double ret = 0.0;
  REP(k, n) { ret += vect[i][k] * vect[j][k]; }
  return ret;
}
double calc(int i, int j) {
  double ret = 0.0;
  ret += Len(j) - square(Inner(j, i)) / Len(i);
  return ret;
}
 
int main() {
  while (scanf("%d %d", &n, &m) > 0) {
    REP(i, m) {
      REP(j, n) {
        scanf("%lf", &vect[i][j]);
      }
    }
    Graph g(m + 1);
    REP(i, m) {
      g[m].push_back(Edge(m, i, Len(i)));
    }
    REP(i, m) {
      REP(j, m) {
        if (i == j) { continue; }
        g[i].push_back(Edge(i, j, calc(i, j)));
      }
    }
    double ans = Arborescence(g, m);
    printf("%.8f\n", ans);
  }
}

Measured memory_bytes: 7936