#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <iomanip>

using namespace std;

const int N = 111;
const double eps = 1e-10;
int n, m, pos[N];
double v[N][N], val[N], dist[N][N];

double get_r(int i, int j)
{
    double up = 0.0;
    double down = 0.0;
    for (int k = 1; k <= n; ++k) {
        up += v[j][k] * v[i][k];
        down += v[j][k] * v[j][k];
    }
    if (fabs(down) < eps) return 0;
    return up / down;
}

bool cmp(const int &x, const int &y) {
    return y < x;
}

namespace EdmondsAlgorithm { // O(ElogE + V^2) !!! 0-based !!!
    const int maxn = 111;
    const int maxm = maxn * maxn;
    struct enode {
        int from, dep;
        double c, key, delta;
        enode *ch[2], *next;
    } ebase[maxm], *etop, *fir[maxn], nil, *null, *inEdge[maxn], *chs[maxn];
    typedef enode *edge; typedef enode *tree;
    int n, m, setFa[maxn], deg[maxn], que[maxn];
    inline void pushDown(tree x) { if (x->delta) {
            x->ch[0]->key += x->delta; x->ch[0]->delta += x->delta;
            x->ch[1]->key += x->delta; x->ch[1]->delta += x->delta; x->delta = 0;
        }}
    tree merge(tree x, tree y) {
        if (x == null) return y; if (y == null) return x;
        if (x->key > y->key) swap(x, y); pushDown(x); x->ch[1] = merge(x->ch[1], y);
        if (x->ch[0]->dep < x->ch[1]->dep) swap(x->ch[0], x->ch[1]);
        x->dep = x->ch[1]->dep + 1; return x;
    }
    void addEdge(int u, int v, double w) {
        etop->from = u; etop->c = etop->key = w; etop->delta = etop->dep = 0;
        etop->next = fir[v]; etop->ch[0] = etop->ch[1] = null;
        fir[v] = etop; inEdge[v] = merge(inEdge[v], etop++);
    }
    void deleteMin(tree &r) { pushDown(r); r = merge(r->ch[0], r->ch[1]); }
    int findSet(int x) { return setFa[x] == x ? x : setFa[x] = findSet(setFa[x]); }
    void clear(int V, int E) {
        null = &nil; null->ch[0] = null->ch[1] = null; null->dep = -1;
        n = V; m = E; etop = ebase;
        for (int i = 0; i < V; ++i) fir[i] = NULL;
        for (int i = 0; i < V; ++i) inEdge[i] = null;
    }
    double solve(int root) {
        double res = 0;
        int head, tail;
        for (int i = 0; i < n; ++i) setFa[i] = i;
        for ( ; ; ) { memset(deg, 0, sizeof(int) * n); chs[root] = inEdge[root];
            for (int i = 0; i < n; ++i) if (i != root && setFa[i] == i) {
                    while (findSet(inEdge[i]->from) == findSet(i)) deleteMin(inEdge[i]);
                    ++deg[ findSet((chs[i] = inEdge[i])->from) ];
                }
            for (int i = head = tail = 0; i < n; ++i)
                if (i != root && setFa[i] == i && deg[i] == 0) que[tail++] = i;
            while (head < tail) {
                int x = findSet(chs[que[head++]]->from);
                if (--deg[x] == 0) que[tail++] = x;
            } bool found = false;
            for (int i = 0; i < n; ++i) if (i != root && setFa[i] == i && deg[i] > 0) {
                    int j = i; tree temp = null; found = true;
                    do {setFa[j = findSet(chs[j]->from)] = i;
                        deleteMin(inEdge[j]); res += chs[j]->key;
                        inEdge[j]->key -= chs[j]->key; inEdge[j]->delta -= chs[j]->key;
                        temp = merge(temp, inEdge[j]);
                    } while (j != i); inEdge[i] = temp;
                } if (!found) break;
        } for (int i = 0; i < n; ++ i) if (i != root && setFa[i] == i) res += chs[i]->key;
        return res;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    double max_val = 0;
    for (int i = 1; i <= m; ++i) {
        val[i] = 0.0;
        for (int j = 1; j <= n; ++j) {
            cin >> v[i][j];
            val[i] += v[i][j] * v[i][j];
        }
    }
    
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= m; ++j) {
            dist[j][i] = 0.0;
            double r = get_r(i, j);
            for (int k = 1; k <= n; ++k)
                dist[j][i] += (v[i][k] - r * v[j][k]) * (v[i][k] - r * v[j][k]);
            max_val += dist[j][i];
        }
    }
    max_val *= 2.0;
    for (int i = 1; i <= m; ++i)
        dist[i][m + 1] = dist[m + 1][i] = max_val + val[i];

    EdmondsAlgorithm::clear(m + 1, (m + 1) * (m + 1));
    for (int i = 1; i <= m + 1; ++i)
        for (int j = 1; j <= m + 1; ++j)
            EdmondsAlgorithm::addEdge(i - 1, j - 1, dist[i][j]);
    double ans = EdmondsAlgorithm::solve(m) - max_val;

    cout << setiosflags(ios::fixed) << setprecision(10) << ans << endl;
    return 0;
}