#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <cassert>
#include <queue>
#include <set>
#include <map>
#include <valarray>
#include <bitset>
#include <stack>
#include <iomanip>
#include <fstream>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define chmax(a,b) (a<b?(a=b,1):0)
#define chmin(a,b) (a>b?(a=b,1):0)
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
const int INF = 1<<29;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef long long ll;
typedef pair<int,int> pii;

typedef double Weight;
struct Edge {
  int src, dst;
  Weight weight;
  Edge(int src, int dst, Weight weight) :
    src(src), dst(dst), weight(weight) { }
};
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;

typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void backward_traverse(int v, int s, int r, Matrix &g,
  vector<int> &no, vector< vector<int> > &comp,
  vector<int> &prev, vector<Weight> &mcost,
  vector<int> &mark, Weight &cost, bool &found) {
  const int n = g.size();
  if (mark[v]) {
    vector<int> temp = no;
    found = true;
    do {
      cost += mcost[v];
      v = prev[v];
      if (v != s) {
        while (comp[v].size() > 0) {
          no[comp[v].back()] = s;
          comp[s].push_back(comp[v].back());
          comp[v].pop_back();
        }
      }
    } while (v != s);
    for (int j = 0; j < n; ++j)
      if (j != r && no[j] == s)
        for (int i = 0; i < n; ++i)
          if (no[i] != s && g[i][j] < INF)
            g[i][j] -= mcost[ temp[j] ];
  }
  mark[v] = true;
  for (int i = 0; i < n; ++i)
    if (no[i] != no[v] && prev[ no[i] ] == v)
      if (!mark[ no[i] ] || i == s)
        backward_traverse(i, s, r, g,
            no, comp, prev, mcost, mark, cost, found);
}

Weight minimum_spanning_arborescence(int r, Matrix &g) {
  const int n = g.size();

  vector<int> no(n);
  vector< vector<int> > comp(n);
  for (int i = 0; i < n; ++i) {
    no[i] = i;
    comp[i].push_back(i);
  }
  Weight cost = 0;
  while (1) {
    vector<int> prev(n, -1);
    vector<Weight> mcost(n, INF);
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        if (j == r) continue;
        if (no[i] != no[j] && g[i][j] < INF) {
          if (g[i][j] < mcost[ no[j] ]) {
            mcost[ no[j] ] = g[i][j];
            prev[ no[j] ] = no[i];
          }
        }
      }
    }
    bool stop = true;
    vector<int> mark(n);
    for (int i = 0; i < n; ++i) {
      if (i == r || mark[i] || comp[i].size() == 0) continue;
      bool found = false;
      backward_traverse(i, i, r, g,
          no, comp, prev, mcost, mark, cost, found);
      if (found) stop = false;
    }
    if (stop) {
      for (int i = 0; i < n; ++i)
        if (prev[i] >= 0)
          cost += mcost[i];
      return cost;
    }
  }
}

double v[100][100];
int n, m;
double dot(int i, int j) {
  double res = 0;
  REP(k,n) {
    res += v[i][k] * v[j][k];
  }
  return res;
}

double cost(int i, int j) {
  if (dot(i,i) < EPS) return dot(j,j);
  double r = dot(i,j) / dot(i,i);
  double res = 0;
  REP(k,n) {
    double t = v[j][k] - r * v[i][k];
    res += t * t;
  }
  return res;
}

int main() {
  while(cin>>n>>m) {
    REP(i,m) REP(j,n) cin>>v[i][j];
    Matrix g(m+1,Array(m+1,INF));
    REP(i,m) {
      REP(j,m) {
        if (i==j) continue;
        g[i][j] = cost(i,j);
      }
      g[m][i] = dot(i,i);
    }
    // REP(i,m+1) {
    //   REP(j,m+1) {
    //     cout << g[i][j] << " ";
    //   }
    //   cout << endl;
    // }
    double res = minimum_spanning_arborescence(m,g);
    printf("%.10f\n", res);
  }
}

Measured memory_bytes: 1432