#include <bits/stdc++.h>

using namespace std;

#define int long long
#define all(v) (v).begin(), (v).end()
#define resz(v, ...) (v).clear(), (v).resize(__VA_ARGS__)
#define reps(i, m, n) for(int i = (int)(m); i < (int)(n); i++)
#define rep(i, n) reps(i, 0, n)

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

using Pi = pair<int, int>;
using Tapris = tuple<int, int, int>;
using vint = vector<int>;

const int inf = 1LL << 55;
const int mod = 1e9 + 7;

struct SCC {
  using Graph = vector<vector<int> >;
  Graph graph, rgraph;
  vector<int> cmp;
  SCC(int V):graph(V), rgraph(V), cmp(V, -1){}
  void add_edge(int from, int to) {
    graph[from].push_back(to);
    rgraph[to].push_back(from);
  }
  void dfs(const Graph& graph, int u, vector<int>& ord, vector<bool>& used) {
    used[u] = true;
    for(int v : graph[u]) {
      if(!used[v]) dfs(graph, v, ord, used);
    }
    ord.push_back(u);
  }
  void rdfs(const Graph& rgraph, int u, int id) {
    cmp[u] = id;
    for(int v : rgraph[u]) {
      if(cmp[v] == -1) rdfs(rgraph, v, id);
    }
  }
  int build() {
    int n = graph.size();
    vector<int> ord;
    vector<bool> used(n, false);
    for(int u = 0; u < n; ++u) {
      if(!used[u]) dfs(graph, u, ord, used);
    }
    reverse(ord.begin(), ord.end());
    int sz = 0;
    for(int u : ord) {
      if(cmp[u] == -1) rdfs(rgraph, u, sz), ++sz;
    }
    return sz;
  }
};
template<typename Weight>
struct ChuLiu_Edmonds {
  struct edge {
    int to;
    Weight cost;
    edge(){}
    edge(int to, Weight cost):to(to), cost(cost){}
  };
  using WeightedGraph = vector< vector<edge> >;
  WeightedGraph graph;
  vector<int> indeg;

  Weight inf;

  ChuLiu_Edmonds(int V, Weight inf):graph(V), indeg(V, 0), inf(inf){}

  void add_edge(int from, int to, Weight cost) {
    graph[from].emplace_back(to, cost);
    indeg[to]++;
  }
  int get_root() {
    for(int r = 0; r < (int)graph.size(); r++) {
      if(indeg[r] == 0) return r;
    }
    return -1;
  }
  Weight minimum_cost_arborescence(WeightedGraph &g, int root) {
    int N = g.size();

    vector<int> into(N, -1);
    vector<Weight> mincost(N, inf); // 頂点uに入るコストが最小の入る辺のfromとそのコスト
    for(int u = 0; u < N; u++) {
      for(edge& e : g[u]) {
	if(e.cost < mincost[e.to]) {
	  into[e.to] = u;
	  mincost[e.to] = e.cost;
	}
      }
    }

    Weight res = 0;
    SCC scc(N);
    for(int u = 0; u < N; u++) {
      if(u == root) continue;
      assert(into[u] != -1);
      assert(mincost[u] != inf);
      scc.add_edge(into[u], u);
      res += mincost[u];
    }
    int scc_sz = scc.build();
    if((int)scc_sz == N) return res;

    WeightedGraph reduce_g(scc_sz);
    for(int u = 0; u < N; u++) {
      for(edge& e : g[u]) {
	if(scc.cmp[u] == scc.cmp[e.to]) continue;
	reduce_g[scc.cmp[u]].emplace_back(scc.cmp[e.to], e.cost-mincost[e.to]);
      }
    }

    return res + minimum_cost_arborescence(reduce_g, scc.cmp[root]);
  }
  Weight build(int root = -1) {
    if(root == -1) root = get_root();
    return minimum_cost_arborescence(graph, root);
  }
};

double sq(double x) {
  return x*x;
}

signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  int N, M;
  cin >> N >> M;
  vector<vector<double> > vec(M, vector<double>(N));
  rep(i, M) rep(j, N) cin >> vec[i][j];

  vector<vector<double> > cost(M, vector<double>(M, inf));
  rep(i, M) {
    cost[i][i] = 0;
    rep(k, N) cost[i][i] += sq(vec[i][k]);
  }
  rep(i, M) rep(j, M) {
    if(i == j) continue;
    if(cost[i][i] == 0) {
      cost[i][j] = cost[j][j];
    } else {
      double r = 0;
      rep(k, N) r += vec[i][k]*vec[j][k];
      r /= cost[i][i];
      cost[i][j] = 0;
      rep(k, N) cost[i][j] += sq(vec[j][k]-r*vec[i][k]);
    }
  }

  ChuLiu_Edmonds<double> mca(M+1, DBL_MAX/2);
  rep(i, M) {
    mca.add_edge(M, i, cost[i][i]);
    rep(j, M) {
      if(i == j) continue;
      mca.add_edge(i, j, cost[i][j]);
    }
  }
  cout << mca.build(M) << endl;


  return 0;
}



Measured memory_bytes: 9696