// Slower C++ solution:
#include <cstdlib>

#include <cctype>

#include <cstring>

#include <cstdio>

#include <cmath>

#include <algorithm>

#include <vector>

#include <string>

#include <iostream>

#include <sstream>

#include <map>

#include <set>

#include <queue>

#include <stack>

#include <ctime>

using namespace std;

typedef long long ll;

#define clr(x,a) memset(x,a,sizeof(x))

#define sz(x) (int)x.size()

#define see(x) cerr<<#x<<" "<<x<<endl

#define se(x) cerr<<" "<<x 

#define pb push_back

#define mk make_pair

#define X first

#define Y second

#define maxn 205

#define maxm 11005

#define type double 

double sqr(double x)

{

	return x*x;

}

const int inf = ~0u >> 1;

struct edge

{

    int u,v;

    type cost;

    int oldu,oldv;

    edge(){}

    edge(int a,int b,type c,int d,int e):u(a),v(b),cost(c),oldu(d),oldv(e){}

}e[maxm];

int pre[maxn],id[maxn],vis[maxn];

int mark;

type in[maxn];

type dirmst(int root,int nv,int ne)

{

    type ret = 0;

    int cnt = 0;

    int oldroot = root;

    while(1)

    {

        cnt++;

        fill(in,in + nv,inf);

        for(int i = 0;i < ne;i++)

        {

            int u = e[i].u;

            int v = e[i].v;

            if(e[i].cost < in[v] && u != v)

            {

                if(e[i].oldu == oldroot)

                    mark = e[i].oldv;

                pre[v] = u;

                in[v] = e[i].cost;

            }

        }

        for(int i = 0;i <nv;i++)

        {

            if(i == root)

                continue;

            if(in[i] == inf)

                return -1;

        }

        int cntnode = 0;

        fill(id,id + nv,-1);

        fill(vis,vis + nv,-1);

        in[root] = 0;

        for(int i = 0;i < nv;i++)

        {

            ret += in[i];

            int v = i;

            while(vis[v] != i && id[v] == -1 && v != root)

            {

                vis[v] = i;

                v = pre[v];

            }

            if(v != root && id[v] == -1)

            {

                for(int u = pre[v];u != v;u = pre[u])

                    id[u] = cntnode;

                id[v] = cntnode++;

            }

        }

        if(cntnode == 0)

            break;

        for(int i = 0;i < nv;i++)

            if(id[i] == -1)

                id[i] = cntnode++;

        for(int i = 0;i < ne;i++)

        {

            int v = e[i].v;

            e[i].u = id[e[i].u];

            e[i].v = id[e[i].v];

            if(e[i].u != e[i].v)

                e[i].cost -= in[v];

        }

        nv = cntnode;

        root = id[root];

    }

    return ret;

}



int n,m;

double dv[maxn],db[maxn][maxn];

double g[maxn][maxn],f[maxn][maxn];

void init()

{

	int i,j,k;

	clr(g,0);

	clr(dv,0);

	clr(db,0);

	for(i=1; i<=n;i++)

	{

		for(j=1; j<=m; j++)

		{

			scanf("%lf",&g[i][j]);

			dv[i]+=sqr(g[i][j]);

		}

	}

	for(i=1; i<=n ;i++)

	for(j=1; j<=n ;j++)

	{

		for(k=1; k<=m; k++)

		{

			db[i][j]+=g[i][k]*g[j][k];

		}

	}

}



int main()

{

	//freopen("in","r",stdin);

	int i,j,k;

    while(scanf("%d %d",&m,&n) == 2)

    {

    	init();

        int sum = 0;

        mark = -1;

        int el=0;

        clr(f,0);

        for(i=1; i<=n; i++)

        {

        	j=0;

        	f[j][i]=dv[i];

        	e[el++] = edge(j,i,f[j][i],j,i);

        	for(j=1; j<=n; j++)

        	if(i!=j)

        	{

        		f[j][i]=(dv[j]*dv[i]-db[i][j]*db[i][j])/dv[j];

        		e[el++] = edge(j,i,f[j][i],j,i);

        	}

        }

		

        double ans = dirmst(0,n + 1,el);

        printf("%.6f\n",ans);

    }

}

// Faster C++ solution for the same problem (measured speedup: 1.9504559502564118x):
#include <bits/stdc++.h>

using namespace std;

const int N = 100 + 10;

const int M = 10000 + 10;

struct edge

{

    int u, v;

    double cost;

    edge() {}

    edge(int u, int v, double c): u(u), v(v), cost(c) {}

} e[M];

int pre[N], hash1[N], vis[N];

double In[N];

double Directed_MST(int root, int n, int m)

{

    double ret = 0;

    while(true)

    {

        for(int i = 0; i < n; i++)

            In[i] = INT_MAX;

        for(int i = 0; i < m; i++) //找最小入?

        {

            int u = e[i].u;

            int v = e[i].v;

            if(e[i].cost < In[v] && u != v)

            {

                pre[v] = u;

                In[v] = e[i].cost;

            }

        }

        for(int i = 0; i < n; i++)

        {

            if(i == root)

                continue;

            if(In[i] == INT_MAX)

                return -1;

        }

        int cntnode = 0;

        memset(hash1, -1, sizeof(hash1));

        memset(vis, -1, sizeof(vis));

        In[root] = 0;

        for(int i = 0; i < n; i++) //找?

        {

            ret += In[i];

            int v = i;

            while(vis[v] != i && hash1[v] == -1 && v != root)

            {

                vis[v] = i;

                v = pre[v];

            }

            if(v != root && hash1[v] == -1)

            {

                for(int u = pre[v]; u != v; u = pre[u])

                    hash1[u] = cntnode;

                hash1[v] = cntnode++;

            }

        }

        if(cntnode == 0)

            break;

        for(int i = 0; i < n; i++)

            if(hash1[i] == -1)

                hash1[i] = cntnode++;

        for(int i = 0; i < m; i++) //重??

        {

            int v = e[i].v;

            e[i].u = hash1[e[i].u];

            e[i].v = hash1[e[i].v];

            if(e[i].u != e[i].v)

                e[i].cost -= In[v];

        }

        n = cntnode;

        root = hash1[root];

    }

    return ret;

}

int n, m;

const int MAXV = 100 + 10;

double vc[MAXV][MAXV];

double A, B, C;

inline double calCost(double r)

{

    return A - r * B + r * r * C;

}

const double EPS = 1e-10;

inline int sgn(double x) {return x < -EPS ? -1 : x > EPS ? 1 : 0;}

int main()

{

#ifdef ACM_TEST

    freopen("in.txt", "r", stdin);

//	freopen("in.txt", "w", stdout);

#endif

    scanf("%d%d", &m, &n);

    for(int i = 1; i <= n; ++i)

        for(int j = 0; j < m; ++j)

            scanf("%lf", &vc[i][j]);

    int tot = 0;

    for(int i = 1; i <= n; ++i)

    {

        double val = 0.0;

        for(int j = 0; j < m; ++j)

            val += vc[i][j] * vc[i][j];

        e[tot++] = edge(0, i, val);

    }

    for(int i = 1; i <= n; ++i)

        for(int j = 1; j <= n; ++j)

        {

            if(i == j) continue;

            A = 0, B = 0, C = 0;

            for(int k = 0; k < m; ++k)

            {

                A += vc[i][k] * vc[i][k];

                B += 2.0 * vc[i][k] * vc[j][k];

                C += vc[j][k] * vc[j][k];

            }

            double l = -1e8, r = 1e8, ll, rr;

            for(int k = 0; k < 100; ++k)

            {

                ll = (l + l + r) / 3.0;

                rr = (l + r + r) / 3.0;

                if(sgn(calCost(ll) - calCost(rr)) >= 0) l = ll;

                else r = rr;

            }

            e[tot++] = edge(j, i, calCost(l));

        }

    double ans = Directed_MST(0, n + 1, tot);

    printf("%.10f\n", ans);

    return 0;

}