/*
* Copyright (c) 2024 Emon Thakur
* All rights reserved.
*/
#include<bits/stdc++.h>
using namespace std;
struct DSU{
int par[2005],sz[2005];
void create(int u)
{
par[u] = u;
sz[u]=1;
}
int findpar(int u)
{
if(par[u]==u) return u;
return par[u] = findpar(par[u]);
}
void Union(int u,int v)
{
int a = findpar(u);
int b = findpar(v);
if(sz[a] < sz[b]) swap(a,b);
par[b] = a;
sz[a] += b;
}
}dsu;
bool cmp(vector<int>&a,vector<int>&b) {return a>b;}
int main()
{
int n,k; cin >> n >> k;
int a[n][k];
for(int i=0;i<n;i++)
{
for(int j=0;j<k;j++) cin >> a[i][j];
}
if(n==1)
{
cout<<0<<endl;
return 0;
}
//priority_queue<vector<int>>pq;
vector<vector<int>> pq(0,vector<int>(3));
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
int cost = 0;
for(int m=0;m<k;m++) cost += abs(a[i][m]-a[j][m]);
pq.push_back({cost,i,j});
}
}
sort(pq.begin(),pq.end(),cmp);
int need = n-2;
vector<int> x = pq[0];
long long ans = x[0];
int taken[n+1]={0};
dsu.create(x[1]);
dsu.create(x[2]);
dsu.Union(x[1],x[2]);
taken[x[1]]=1;
taken[x[2]]=1;
int edge = 1,ind = 1;
while(edge != n-1)
{
x = pq[ind++];
if(taken[x[1]] && taken[x[2]])
{
if(dsu.findpar(x[1]) == dsu.findpar(x[2])) continue;
edge++;
dsu.Union(x[1],x[2]);
}
else if(taken[x[1]])
{
dsu.create(x[2]);
taken[x[2]]++;
dsu.Union(x[1],x[2]);
++edge;
}
else if(taken[x[2]])
{
dsu.create(x[1]);
taken[x[1]]++;
dsu.Union(x[1],x[2]);
++edge;
}
else
{
dsu.create(x[1]);
dsu.create(x[2]);
dsu.Union(x[1],x[2]);
taken[x[1]]++;
taken[x[2]]++;
edge++;
}
ans += x[0];
}
cout << ans << endl;
}