#include <cstdio>
#include <cstring>
#include <algorithm>

const int N=17,M=1e4+5;
const int INF=1<<30;
int n,m,a[N][M],f[1<<N][N],g[N][N],h[N][N];

void init() {
	for(int i=0;i<n;++i) for(int j=0;j<n;++j) {
		g[i][j]=INF,h[i][j]=INF;
		for(int k=1;k<=m;++k) g[i][j]=std::min(g[i][j],std::abs(a[i][k]-a[j][k]));
		for(int k=2;k<=m;++k) h[i][j]=std::min(h[i][j],std::abs(a[i][k-1]-a[j][k]));
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i) for(int j=1;j<=m;++j) scanf("%d",&a[i][j]);
	init();

	for (register int i=0; i<n; ++i)
	for (register int j=0; j<=n; ++j)
	{
//		printf("i=%d j=%d h[i][j]=%d\n",i,j,h[i][j]);
	}

	int ans=0;
	for(int k=0;k<n;++k) {
		memset(f,0,sizeof(f));
		f[1<<k][k]=INF;
		for(int S=0;S<(1<<n);++S) for(int i=0;i<n;++i) if(S&(1<<i)) {
			for(int j=0;j<n;++j) {
				if(!(S&(1<<j))) f[S|(1<<j)][j]=std::max(f[S|(1<<j)][j],std::min(f[S][i],g[i][j]));
			}
		}
		for(int i=0;i<n;++i) {
			ans=std::max(ans,std::min(f[(1<<n)-1][i],h[k][i]));
		}
	}
	printf("%d\n",ans);
	return 0;
}


#include<iostream>
#include<cstring>

using namespace std;

const int MAXN = 17;
const int MAXM = 1e4 + 5;
const int inf = 1e9 + 5;

int n, m;
int a[MAXN][MAXM];

int memo[1<<MAXN][MAXN][MAXN];
int rowValMid[MAXN][MAXN], rowValLast[MAXN][MAXN];

int calcState(int mask, int first, int last, int placed)
{
    if(mask==(1<<n)-1)
    {
        return inf;
    }
    if(memo[mask][first][last]!=-1)
    {
        return memo[mask][first][last];
    }

    int answer = 0;
    for(int row = 0;row<n;row++)
    {
        if(((mask>>row)&1)==1) continue;

        int curr = min(rowValMid[last][row], calcState(mask|(1<<row), first, row, placed+1));
        if(placed==n-1) curr = min(curr, rowValLast[last][row]);

        answer = max(answer, curr);
    }

    memo[mask][first][last] = answer;
    return answer;
}

int myAbs(int x)
{
    return max(x, -x);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> m;
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<m;j++)
        {
            cin >> a[i][j];
        }
    }

    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = r1+1;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m;j++)
            {
                minVal = min(minVal, myAbs(a[r1][j]-a[r2][j]));
            }

            rowValMid[r1][r2] = rowValMid[r2][r1] = minVal;
        }
    }
    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = 0;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m-1;j++)
            {
                minVal = min(minVal, myAbs(a[r2][j]-a[r1][j+1]));
            }

            rowValLast[r1][r2] = minVal;
        }
    }

    int answer = 0;
    memset(memo, -1, sizeof(memo));

    for(int i = 0;i<n;i++)
    {
        answer = max(answer, calcState((1<<i), i, i, 1));
    }

    cout << answer << '\n';
}


#include<iostream>
#include<cstring>

using namespace std;

const int MAXN = 17;
const int MAXM = 1e4 + 5;
const int inf = 1e9 + 5;

int n, m;
int a[MAXN][MAXM];

int memo[1<<MAXN][MAXN][MAXN];
int rowValMid[MAXN][MAXN], rowValLast[MAXN][MAXN];

int calcState(int mask, int first, int last, int placed)
{
    if(mask==(1<<n)-1)
    {
        return inf;
    }
    if(memo[mask][first][last]!=-1)
    {
        return memo[mask][first][last];
    }

    int answer = 0;
    for(int row = 0;row<n;row++)
    {
        if(((mask>>row)&1)==1) continue;

        int curr = min(rowValMid[last][row], calcState(mask|(1<<row), first, row, placed+1));
        if(placed==n-1) curr = min(curr, rowValLast[first][row]);

        answer = max(answer, curr);
    }

    memo[mask][first][last] = answer;
    return answer;
}

int myAbs(int x)
{
    return max(x, -x);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> m;
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<m;j++)
        {
            cin >> a[i][j];
        }
    }

    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = r1+1;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m;j++)
            {
                minVal = min(minVal, myAbs(a[r1][j]-a[r2][j]));
            }

            rowValMid[r1][r2] = rowValMid[r2][r1] = minVal;
        }
    }
    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = 0;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m-1;j++)
            {
                minVal = min(minVal, myAbs(a[r2][j]-a[r1][j+1]));
            }

            rowValLast[r1][r2] = minVal;
        }
    }

    if(n==1)
    {
        cout << rowValLast[0][0] << '\n';
        return 0;
    }

    int answer = 0;
    memset(memo, -1, sizeof(memo));

    for(int i = 0;i<n;i++)
    {
        answer = max(answer, calcState((1<<i), i, i, 1));
    }

    cout << answer << '\n';
}


#include<iostream>
#include<cstring>

using namespace std;

const int MAXN = 17;
const int MAXM = 1e4 + 5;
const int inf = 1e9 + 5;

int n, m;
int a[MAXN][MAXM];

int memo[1<<MAXN][MAXN][MAXN];
int rowValMid[MAXN][MAXN], rowValLast[MAXN][MAXN];

int calcState(int mask, int first, int last, int placed)
{
    if(mask==(1<<n)-1)
    {
        return inf;
    }
    if(memo[mask][first][last]!=-1)
    {
        return memo[mask][first][last];
    }

    int answer = 0;
    for(int row = 0;row<n;row++)
    {
        if(((mask>>row)&1)==1) continue;

        int curr = min(rowValMid[last][row], calcState(mask|(1<<row), first, row, placed+1));
        if(placed==n-1) curr = min(curr, rowValLast[last][row]);

        answer = max(answer, curr);
    }

    memo[mask][first][last] = answer;
    return answer;
}

int myAbs(int x)
{
    return max(x, -x);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> m;
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<m;j++)
        {
            cin >> a[i][j];
        }
    }

    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = r1+1;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m;j++)
            {
                minVal = min(minVal, myAbs(a[r1][j]-a[r2][j]));
            }

            rowValMid[r1][r2] = rowValMid[r2][r1] = minVal;
        }
    }
    for(int r1 = 0;r1<n;r1++)
    {
        for(int r2 = 0;r2<n;r2++)
        {
            int minVal = inf;
            for(int j = 0;j<m-1;j++)
            {
                minVal = min(minVal, myAbs(a[r2][j]-a[r1][j+1]));
            }

            rowValLast[r1][r2] = minVal;
        }
    }

    if(n==1)
    {
        cout << rowValLast[0][0] << '\n';
        return 0;
    }

    int answer = 0;
    memset(memo, -1, sizeof(memo));

    for(int i = 0;i<n;i++)
    {
        answer = max(answer, calcState((1<<i), i, i, 1));
    }

    cout << answer << '\n';
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
    }
    return dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
   // freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);//==  (1<<n)-1
    int ans=0;
    if(n==1)
    {
        cout<<mn2[0][0];
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            if(i==j)continue;
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[j][i]),ans);
        }
    }
    cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
void bit(int x)
{
    while(x)
    {
        cout<<x%2;
        x/=2;
    }
    cout<<endl;
}
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        {
            dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
        }
    }
    return dp[state][pos]==-1?(0x3f3f3f3f):dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
    //freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);
    //bit(ed);
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[i][j]),ans);
        }
    }
    cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
void bit(int x)
{
    while(x)
    {
        cout<<x%2;
        x/=2;
    }
    cout<<endl;
}
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        {
            dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
        }
    }
    return dp[state][pos]==-1?(0x3f3f3f3f):dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
   // freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);
    //bit(ed);
    int ans=0;
    if(n==1)
    {
        cout<<mn2[0][0];
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            if(i==j)continue;
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[i][j]),ans);
        }
    }
    cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
void bit(int x)
{
    while(x)
    {
        cout<<x%2;
        x/=2;
    }
    cout<<endl;
}
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        {
            dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
        }
    }
    return dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
    //freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);
    //bit(ed);
    int ans=mn2[0][0];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            if(i==j)continue;
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[i][j]),ans);
        }
    }
    cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
void bit(int x)
{
    while(x)
    {
        cout<<x%2;
        x/=2;
    }
    cout<<endl;
}
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        {
            dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
        }
    }
    return dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
    //freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);
    //bit(ed);
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            if(i==j)continue;
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[i][j]),ans);
        }
    }
    cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=18,M=1e4+10;
int mn1[N][N],mn2[N][N],A[N][M],n,m;
int dp[1<<N][N];
void bit(int x)
{
    while(x)
    {
        cout<<x%2;
        x/=2;
    }
    cout<<endl;
}
int dfs(int state,int pos,int ed)
{
    if((1<<ed)==state)
        return mn1[ed][pos];
    if(dp[state][pos]!=-1)return dp[state][pos];
    for(int i=0;i<n;i++)
    {
        int v=1<<i;
        if(i==ed)continue;
        if((v|state)==state)
        {
            dp[state][pos]=max(min(dfs(state-v,i,ed),mn1[i][pos]),dp[state][pos]);
        }
    }
    return dp[state][pos];
}
int main()
{
    ios::sync_with_stdio(0);
    memset(mn1,0x3f,sizeof mn1);
    memset(mn2,0x3f,sizeof mn2);
    memset(A,0x3f,sizeof A);
    memset(dp,0x3f,sizeof dp);
    freopen("i.txt","r",stdin);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>A[i][j];
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<m; k++)
                mn1[i][j]=min(mn1[i][j],abs(A[i][k]-A[j][k]));
            for(int k=0; k<m-1; k++)//i->j
                mn2[i][j]=min(mn2[i][j],abs(A[i][k]-A[j][k+1]));
        }
    }
    ll ed=0;
    for(int i=0;i<n;i++)ed+=(1<<i);
    //bit(ed);
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            memset(dp,-1,sizeof dp);
            if(i==j)continue;
            ans=max(min(dfs(ed-(1<<i),i,j),mn2[i][j]),ans);
        }
    }
    cout<<ans<<endl;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		int ans=1;
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				continue;
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				{
					low[now]=min(low[now],dfn[v]);
					ans=max(ans,dfn[now]-dfn[v]+1);
				}
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7ffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
int dp[200010][21];
class shrinknode{
	public:
		int n,m;
		int mp[21][21];
		int ans;
		void add(int u,int v)
		{
			mp[u-1][v-1]=1;
		}
		void init()
		{
			mst(mp,0);
		}
		int run(int u,int v)
		{
			u--;
			v--;
			int i,j,k;
			ford(i,0,(1<<n)-1)
			{
				ford(j,0,n-1)
				dp[i][j]=inf;
			}
			dp[1][0]=0;
			ford(i,0,(1<<n)-1)
			{
				ford(j,0,n-1)
				{
					if((i>>j)&1)
					ford(k,0,n-1)
					if(k==u&&j!=v)
					continue;
					else if(((i-(1<<j))>>k&1)&&mp[k][j])
					{
						dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+1);
					//	cout<<k<<" "<<j<<endl;
					}
				}
			}
		//	cout<<dp[(1<<n)-1][n-1]<<endl;
			return dp[(1<<n)-1][n-1];
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,i-1)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
		tarjan1.add(j,i);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				if(n==1)
				return true;
				tarjan2=tarjan1;
				tarjan2.add(i,j);
				int temp=tarjan2.run(i,j);
				if(temp==n-1)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 10010
#define inf 0x7fffffff
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
int des[20][maxn];
int first[maxn];
int nex[maxn];
int go[maxn];
int amount;
int n,m;
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abs(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abs(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
int dfs(int now);
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==3)
	//	cout<<i<<" "<<j<<endl;
		add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
			//	if(k==3)
			//	cout<<i<<" "<<j<<endl;
			//	book[i]=1;
				book[j]=1;
				int temp=dfs(j);
			//	if(k==3)
			//	cout<<temp<<endl;
				if(temp==n)
				return true;
			//	book[i]=0;
				book[j]=0;
			}
		}
	}
	return false;
}
int dfs(int now)
{
	int i;
	int ans=0;
	for(i=first[now];i;i=nex[i])
	{
		if(book[go[i]]==0)
		{
			book[go[i]]=1;
			ans=max(ans,dfs(go[i]));
			book[go[i]]=0;
		}
	}
	return ans+1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	int l=0;
	int r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 10010
#define inf 0x7fffffff
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
int des[20][maxn];
int first[maxn];
int nex[maxn];
int go[maxn];
int amount;
int n,m;
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abs(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abs(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
int dfs(int now);
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==3)
	//	cout<<i<<" "<<j<<endl;
		add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j)
			continue;
			else if(check2(i,j,k))
			{
			//	if(k==3)
			//	cout<<i<<" "<<j<<endl;
			//	book[i]=1;
				book[j]=1;
				int temp=dfs(j);
			//	if(k==3)
			//	cout<<temp<<endl;
				if(temp==n)
				return true;
			//	book[i]=0;
				book[j]=0;
			}
		}
	}
	return false;
}
int dfs(int now)
{
	int i;
	int ans=0;
	for(i=first[now];i;i=nex[i])
	{
		if(book[go[i]]==0)
		{
			book[go[i]]=1;
			ans=max(ans,dfs(go[i]));
			book[go[i]]=0;
		}
	}
	return ans+1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	int l=0;
	int r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				low[now]=min(low[now],dfn[v]);
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int first[maxn];
int nex[maxn];
int go[maxn];
int amount;
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
//	cout<<k<<" "<<tarjan1.amount<<endl;
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.taj==1)
				return true;
//				else
//				cout<<k<<" "<<tarjan2.taj<<endl;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int ans;
		void dfs(int now,int step)
		{
			book[now]=1;
			dfn[now]=step;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				if(now==t1&&go[i]!=t2)
				continue;
				if(!book[go[i]])
				dfs(go[i],step+1);
				else
				{
					int temp=dfn[now]-dfn[go[i]]+1;
					if(temp>ans)
					ans=temp;
				}
			}
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.dfs(j,1);
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
int dp[200010][21];
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
int check1(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m)
	minx=min(minx,abss(des[a][i]-des[b][i]));
	return minx;
}
int check2(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m-1)
	minx=min(minx,abss(des[a][i]-des[b][i+1]));
	return minx;
}
int mp[20][20];
int mp2[20][20];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j,k;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ford(i,1,n)
	ford(j,1,n)
	{
		mp[i][j]=check1(i,j);
		mp2[i][j]=check2(i,j);
	//	cout<<i<<" "<<j<<" "<<mp[i][j]<<endl;
	}
	int ans=0;
	ford(i,1,n)
	{
		mst(dp,0);
		dp[1<<(i-1)][i]=inf;
		int a,b;
		ford(j,1,(1<<n)-1)
		ford(a,1,n)
		{
			if((j>>(a-1)&1))
			ford(b,1,n)
			{
				if((j>>(b-1)&1)&&a!=b)
				dp[j][a]=max(dp[j][a],min(dp[j^(1<<(a-1))][b],mp[b][a]));
			}
		}
		ford(j,1,n)
		{
			if(j!=i)
			ans=max(ans,min(dp[(1<<n)-1][j],mp2[j][i]));
		}
	}
	if(n==1)
	cout<<mp2[1][1];
	else
	cout<<ans;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		int ans=1;
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				continue;
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					int temp=nowtime;
					dfs(v,now);
					nowtime=temp;
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				{
					low[now]=min(low[now],dfn[v]);
					ans=max(ans,dfn[now]-dfn[v]+1);
				}
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				low[now]=min(low[now],dfn[v]);
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int first[maxn];
int nex[maxn];
int go[maxn];
int amount;
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
//	cout<<k<<" "<<tarjan1.amount<<endl;
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.taj==1&&tarjan2.bcc[1].size()==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		int ans=1;
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				{
					ans=max(ans,2ll);
					continue;
				}
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					int temp=nowtime;
					dfs(v,now);
					nowtime=temp;
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				{
					low[now]=min(low[now],dfn[v]);
					ans=max(ans,dfn[now]-dfn[v]+1);
				}
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==0)
	//	cout<<i<<" "<<j<<endl;
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
			//	if(k==0)
			//	cout<<i<<" "<<j<<endl;
				tarjan2.tarjan();
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				low[now]=min(low[now],dfn[v]);
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int first[30];
int nex[310];
int go[310];
int amount;
int n,m;
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abs(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abs(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.tarjan();
				if(tarjan2.taj==1)
				return true;
			}
		}
	}
	return false;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	int l=0;
	int r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
int dp[200010][21];
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
int check1(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m)
	minx=min(minx,abss(des[a][i]-des[b][i]));
	return minx;
}
int check2(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m-1)
	minx=min(minx,abss(des[a][i]-des[b][i+1]));
	return minx;
}
int mp[20][20];
int mp2[20][20];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j,k;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ford(i,1,n)
	ford(j,1,n)
	{
		mp[i][j]=check1(i,j);
		mp2[i][j]=check2(i,j);
	//	cout<<i<<" "<<j<<" "<<mp[i][j]<<endl;
	}
	ford(i,1,n)
	dp[1<<(i-1)][i]=inf;
	ford(i,1,(1<<n)-1)
	{
		ford(j,1,n)
		if(i>>(j-1)&1)
		ford(k,1,n)
		{
			if((i>>(k-1)&1)&&j!=k)
			{
				dp[i][j]=max(dp[i][j],min(dp[i^(1<<(j-1))][k],mp[k][j]));
			}
		}
	}
	int ans=0;
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i!=j)
			ans=max(ans,min(dp[(1<<n)-1][j],mp2[j][i]));
		}
	}
	if(n==1)
	cout<<mp2[1][1];
	else
	cout<<ans;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		int ans;
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,0);
			amount=0;
		}
		void dfs(int now,int step)
		{
			book[now]=1;
			dfn[now]=step;
			int i;
			for(i=first[now];i;i=nex[i])
			{
				int v=go[i];
				if(now==t1&&v!=t2)
				continue;
				if(!book[go[i]])
					dfs(go[i],step+1);
				else
				{
					ans=max(ans,dfn[now]-dfn[go[i]]+1);
				}
			}
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==0)
	//	cout<<i<<" "<<j<<endl;
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				if(n==1)
				return true;
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.dfs(j,1);
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		int ans;
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				continue;
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				{
					low[now]=min(low[now],dfn[v]);
					ans=max(ans,dfn[now]-dfn[v]+1);
				}
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		int ans;
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,0);
			amount=0;
		}
		void dfs(int now,int step)
		{
			book[now]=1;
			dfn[now]=step;
			int i;
			for(i=first[now];i;i=nex[i])
			{
				int v=go[i];
				if(now==t1&&v!=t2)
				continue;
				if(!book[go[i]])
					dfs(go[i],step+1);
				else
				{
					ans=max(ans,dfn[now]-dfn[go[i]]+1);
				}
			}
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==0)
	//	cout<<i<<" "<<j<<endl;
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				if(n==1)
				return true;
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.dfs(i,1);
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7ffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
int dp[200010][21];
class shrinknode{
	public:
		int n,m;
		int mp[21][21];
		int ans;
		void add(int u,int v)
		{
			mp[u-1][v-1]=1;
		}
		void init()
		{
			mst(mp,0);
		}
		int run(int u,int v)
		{
			u--;
			v--;
			int i,j,k;
			ford(i,0,n-1)
			mp[u][i]=0;
			mp[u][v]=1;
			ford(i,0,(1<<n)-1)
			{
				ford(j,0,n-1)
				dp[i][j]=inf;
			}
			dp[1][0]=0;
			ford(i,0,(1<<n)-1)
			{
				ford(j,0,n-1)
				{
					if((i>>j)&1)
					ford(k,0,n-1)
					if(((i-(1<<j))>>k&1)&&mp[k][j])
					{
						dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+1);
					//	cout<<k<<" "<<j<<endl;
					}
				}
			}
		//	cout<<dp[(1<<n)-1][n-1]<<endl;
		//	return dp[(1<<n)-1][0];
			ford(i,0,n-1)
			if(dp[(1<<n)-1][i]==n-1&&mp[i][0])
			return n;
			return 0;
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,i-1)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
		tarjan1.add(j,i);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				if(n==1)
				return true;
				tarjan2=tarjan1;
				tarjan2.add(i,j);
				int temp=tarjan2.run(i,j);
			//	if(k==1)
			//	cout<<temp<<endl;
				if(temp==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				continue;
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					dfs(v,now);
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				low[now]=min(low[now],dfn[v]);
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.taj==1&&tarjan2.bcc[1].size()==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7ffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
int dp[200010][21];
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
int check1(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m)
	minx=min(minx,abss(des[a][i]-des[b][i]));
	return minx;
}
int check2(int a,int b)
{
	int i;
	int minx=inf;
	ford(i,1,m-1)
	minx=min(minx,abss(des[a][i]-des[b][i+1]));
	return minx;
}
int mp[20][20];
int mp2[20][20];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j,k;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ford(i,1,n)
	ford(j,1,n)
	{
		mp[i][j]=check1(i,j);
		mp2[i][j]=check2(i,j);
	//	cout<<i<<" "<<j<<" "<<mp[i][j]<<endl;
	}
	ford(i,1,n)
	dp[1<<(i-1)][i]=inf;
	ford(i,1,(1<<n)-1)
	{
		ford(j,1,n)
		if(i>>(j-1)&1)
		ford(k,1,n)
		{
			if((i>>(k-1)&1)&&j!=k)
			{
				dp[i][j]=max(dp[i][j],min(dp[i^(1<<(j-1))][k],mp[k][j]));
			}
		}
	}
	int ans=0;
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i!=j)
			ans=max(ans,min(dp[(1<<n)-1][j],mp2[j][i]));
		}
	}
	if(n==1)
	cout<<mp2[1][1];
	else
	cout<<ans;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 10010
#define inf 0x7fffffff
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
int des[20][maxn];
int first[maxn];
int nex[maxn];
int go[maxn];
int amount;
int n,m;
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abs(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abs(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
void add(int u,int v)
{
	go[++amount]=v;
	nex[amount]=first[u];
	first[u]=amount;
}
int book[maxn];
int dfs(int now);
bool check(int k)
{
	amount=0;
	mst(first,0);
	mst(book,0);
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==3)
	//	cout<<i<<" "<<j<<endl;
		add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(check2(i,j,k))
			{
			//	if(k==3)
			//	cout<<i<<" "<<j<<endl;
			//	book[i]=1;
				book[j]=1;
				int temp=dfs(j);
			//	if(k==3)
			//	cout<<temp<<endl;
				if(temp==n)
				return true;
			//	book[i]=0;
				book[j]=0;
			}
		}
	}
	return false;
}
int dfs(int now)
{
	int i;
	int ans=0;
	for(i=first[now];i;i=nex[i])
	{
		if(book[go[i]]==0)
		{
			book[go[i]]=1;
			ans=max(ans,dfs(go[i]));
			book[go[i]]=0;
		}
	}
	return ans+1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	int l=0;
	int r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <memory>
using namespace std;
#define sf(a) scanf("%d",&a)
#define pf(a) printf("%d",a)
#define ford(i,a,n) for(i=a;i<=n;++i)
#define forb(i,n,a) for(i=n;i>=a;--i)
#define mst(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define pb push_back
#define ddd cout<<"ddd"<<endl
#define maxn 310
#define inf 0x7fffffff
#define int ll
const ll mod=1e9+7;
// 15 memset ll上限;
// 63 memset int上限;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937 myrand(seed);
uniform_int_distribution<ll>dist(0,5);//设定随机范围;
// dist(myrand); 这就是个在范围内的随机数;
ll read()
{
    ll x=0,flag=0;
    char ch=getchar();
    if(ch=='-') flag=1;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
    if(flag) return -x;
    return x;
}
ll power(ll a,ll n)
{
	ll sum=1;
	while(n)
	{
		if(n&1)
		sum*=a;
		sum%=mod;
		a*=a;
		a%=mod;
		n>>=1;
	}
	return sum%mod;;
}
ll ny(ll n)
{
	return power(n,mod-2);
}
class shrinknode{
	public:
		int n,m;
		int first[maxn];
		int nex[maxn];
		int go[maxn];
		int amount;
		int t1,t2;
		int dfn[maxn];
		int low[maxn];
		int sign[maxn];
		int nowtime,top;
		int book[maxn];
		void add(int u,int v)
		{
			go[++amount]=v;
			nex[amount]=first[u];
			first[u]=amount;
		}
		void init()
		{
			mst(first,-1);
			amount=-1;
		}
		int belong[maxn];
		int taj;
		int stackk[maxn];
		int ans=1;
		vector<int>bcc[maxn];
		void dfs(int now,int fa)
		{
			dfn[now]=low[now]=++nowtime;
			stackk[top++]=now;
			book[now]=1;
			int i;
			for(i=first[now];~i;i=nex[i])
			{
				int v=go[i];
				if(v==fa)
				{
					ans=max(ans,2ll);
					continue;
				}
				if(now==t1&&v!=t2)
				continue;
				if(dfn[v]==-1)
				{
					int temp=nowtime;
					dfs(v,now);
					nowtime=temp;
					low[now]=min(low[now],low[v]);
					if(dfn[now]<low[v])
					sign[i]=1;
				}
				else if(book[v])
				{
					low[now]=min(low[now],dfn[v]);
					ans=max(ans,dfn[now]-dfn[v]+1);
				}
			}
			if(low[now]==dfn[now])
			{
				int temp;
				taj++;
				bcc[taj].clear();
				do{
					temp=stackk[--top];
					book[temp]=0;
					belong[temp]=taj;
					bcc[taj].pb(temp);
				}while(temp!=now);
			}
		}
		void tarjan()
		{
			mst(dfn,-1);
			mst(book,0);
			top=nowtime=taj=0;
			int i;
			ford(i,1,n)
			if(dfn[i]==-1)
			dfs(i,i);
		}
}tarjan1,tarjan2;
int des[20][10010];
int n,m;
int abss(int n)
{
	if(n<0)
	return -n;
	else
	return n;
}
bool check1(int a,int b,int k)
{
	int i;
	ford(i,1,m)
	if(abss(des[a][i]-des[b][i])<k)
	return false;
	return true;
}
bool check2(int a,int b,int k)
{
	int i;
	ford(i,1,m-1)
	if(abss(des[a][i]-des[b][i+1])<k)
	return false;
	return true;
}
bool check(int k)
{
	tarjan1.init();
	tarjan1.n=n;
	int i,j;
	ford(i,1,n)
	ford(j,1,n)
	if(i!=j&&check1(i,j,k))
	{
	//	if(k==0)
	//	cout<<i<<" "<<j<<endl;
		tarjan1.add(i,j);
	}
	ford(i,1,n)
	{
		ford(j,1,n)
		{
			if(i==j&&n>1)
			continue;
			else if(check2(i,j,k))
			{
				if(n==1)
				return true;
				tarjan2=tarjan1;
				tarjan2.t1=i;
				tarjan2.t2=j;
				tarjan2.add(i,j);
				tarjan2.tarjan();
				if(tarjan2.ans==n)
				return true;
			}
		}
	}
	return false;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	//ddd;
	cin>>n>>m;
	int i,j;
	ford(i,1,n)
	ford(j,1,m)
	cin>>des[i][j];
	ll l=0;
	ll r=1e9;
//	cout<<check1(1,4,5)<<endl;
	while(l<r)
	{
		ll mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else
		r=mid-1;
	}
	cout<<l;
}


#include <stdio.h>

int matrix[16][10000];
int mindiff[16][16];
int mindiff1M[16][16];
int order[16];
int visited[16];
int max = 0;

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

void dfs(int depth, int N, int min)
{
	if (min <= max) return;
	if (depth == N)
	{
		int b = mindiff1M[order[N - 1]][order[0]];
		if (min > b) min = b;
		if (max < min) max = min;
		return;
	}
	for (int i = 0; i < N; i++)
	{
		if (visited[i]) continue;
		order[depth] = i;
		visited[i] = 1;
		int omin = min;
		if (depth > 0)
		{
			int mm = mindiff[order[depth - 1]][order[depth]];
			if (min > mm) min = mm;
		}
		dfs(depth + 1, N, min);
		min = omin;
		visited[i] = 0;
	}
}

int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff1M[i][j] = min;
		}
	}
	dfs(0, N, 1000000007);
	printf("%d\n", max);
	return 0;
}


#include <stdio.h>
#define MAX 3010

int matrix[16][10000];
int maxdiff[16][16];
int maxdiff1M[16][16];
int order[16];
int visited[16];
int max = 0;

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

void dfs(int depth, int N)
{
	if (depth == N)
	{
		int min = 1000000007;
		for (int i = 1; i < N; i++)
		{
			int a = maxdiff[order[i - 1]][order[i]];
			if (min > a) min = a;
		}
		int b = maxdiff1M[order[N - 1]][order[0]];
		if (min > b) min = b;
		if (max < min) max = min;
	}
	for (int i = 0; i < N; i++)
	{
		if (visited[i]) continue;
		order[depth] = i;
		visited[i] = 1;
		dfs(depth + 1, N);
		visited[i] = 0;
	}
}

int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff1M[i][j] = min;
		}
	}
	dfs(0, N);
	printf("%d\n", max);
	return 0;
}


#include <stdio.h>
#define MAX 3010

int matrix[16][10000];
int mindiff[16][16];
int mindiff1M[16][16];
int maxmin[65536];
int maxmin1M[16];
int order[16];
int visited;
int max = 0;

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

void dfs(int depth, int N, int min)
{
	if (min <= max) return;
	if (depth == N)
	{
		int b = mindiff1M[order[N - 1]][order[0]];
		if (min > b) min = b;
		if (max < min) max = min;
	}
	for (int i = 0; i < N; i++)
	{
		if ((visited >> i) & 1) continue;
		order[depth] = i;
		visited |= (1 << i);
		int omin = min;
		if (depth > 0)
		{
			int mm = mindiff[order[depth - 1]][order[depth]];
			if (min > mm) min = mm;
		}
		else
		{
			int mm = maxmin1M[i];
			if (min > mm) min = mm;
		}
		if (min > maxmin[visited] && maxmin[visited] >= 0) min = maxmin[visited];
		dfs(depth + 1, N, min);
		min = omin;
		visited &= ~(1 << i);
	}
}

int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff1M[i][j] = min;
		}
	}
	for (int i = 0; i < (1 << N); i++)
	{
		int max = -1;
		for (int j = 0; j < N; j++)
		{
			if (((i >> j) & 1) == 0) continue;
			for (int k = j + 1; k < N; k++)
			{
				if (((i >> k) & 1) == 0) continue;
				if (max < mindiff[j][k]) max = mindiff[j][k];
			}
		}
		maxmin[(1 << N) - i - 1] = max;
	}
	for (int i = 0; i < N; i++)
	{
		int max = 0;
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			if (mindiff1M[j][i] > max) max = mindiff1M[j][i];
		}
		maxmin1M[i] = max;
	}
	if (N == 1) maxmin1M[0] = mindiff1M[0][0];
	dfs(0, N, 1000000007);
	printf("%d\n", max);
	return 0;
}


#include <stdio.h>
#define MAX 3010

int matrix[16][10000];
int maxdiff[16][16];
int maxdiff1M[16][16];
int order[16];
int visited[16];

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

int main()
{
	int N, M;
	int max = 0;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff1M[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (max < maxdiff[i][j]) max = maxdiff[i][j];
			if (max < maxdiff1M[i][j]) max = maxdiff[i][j];
		}
	}
	printf("%d\n", max);
	return 0;
}


#include <stdio.h>
#define MAX 3010

int matrix[16][10000];
int maxdiff[16][16];
int maxdiff1M[16][16];
int order[16];
int visited[16];
int max = 0;

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

void dfs(int depth, int N)
{
	if (depth == N)
	{
		int min = 1000000007;
		for (int i = 1; i < N; i++)
		{
			int a = maxdiff[order[i - 1]][order[i]];
			if (min > a) min = a;
		}
		int b = maxdiff1M[order[N - 1]][order[0]];
		if (min > b) min = b;
		if (max < min) max = min;
	}
	for (int i = 0; i < N; i++)
	{
		if (visited[i]) continue;
		order[depth] = i;
		visited[i] = 1;
		dfs(depth + 1, N);
		visited[i] = 0;
	}
}

int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			maxdiff1M[i][j] = min;
		}
	}
	dfs(0, N);
	printf("%d\n", max);
	return 0;
}


#include <stdio.h>
#define MAX 3010

int matrix[16][10000];
int mindiff[16][16];
int mindiff1M[16][16];
int maxmin[65536];
int maxmin1M[65536];
int order[16];
int visited;
int max = 0;

inline int myabs(int a, int b)
{
	return a > b ? a - b : b - a;
}

void dfs(int depth, int N, int min)
{
	if (min <= max) return;
	if (depth == N)
	{
		int b = mindiff1M[order[N - 1]][order[0]];
		if (min > b) min = b;
		if (max < min) max = min;
	}
	for (int i = 0; i < N; i++)
	{
		if ((visited >> i) & 1) continue;
		order[depth] = i;
		visited |= (1 << i);
		int omin = min;
		if (depth > 0)
		{
			int mm = mindiff[order[depth - 1]][order[depth]];
			if (min > mm) min = mm;
		}
		if (min > maxmin[visited] && maxmin[visited] >= 0) min = maxmin[visited];
		dfs(depth + 1, N, min);
		min = omin;
		visited &= ~(1 << i);
	}
}

int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &matrix[i][j]);
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (i == j) continue;
			int min = 1000000007;
			for (int k = 0; k < M; k++)
			{
				int diff = myabs(matrix[i][k], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff[i][j] = min;
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			int min = 1000000007;
			for (int k = 1; k < M; k++)
			{
				int diff = myabs(matrix[i][k - 1], matrix[j][k]);
				if (diff < min) min = diff;
			}
			mindiff1M[i][j] = min;
		}
	}
	for (int i = 0; i < (1 << N); i++)
	{
		int max = -1;
		for (int j = 0; j < N; j++)
		{
			if (((i >> j) & 1) == 0) continue;
			for (int k = j + 1; k < N; k++)
			{
				if (((i >> k) & 1) == 0) continue;
				if (max < mindiff[j][k]) max = mindiff[j][k];
			}
		}
		maxmin[(1 << N) - i - 1] = max;
	}
	dfs(0, N, 1000000007);
	printf("%d\n", max);
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x7FFFFFFF
#define N 20
#define M 1100
using namespace std;
int a[N][M],n,m,f[N][1<<N],c[N];
inline bool check(int kk){
	memset(c,0,sizeof c);
	memset(f,0,sizeof f);

	for(int i=1;i<=n;++i) c[i]|=(1<<(i-1));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<=m;++k) ans=min(ans,abs(a[i][k]-a[j][k]));
			if(ans>=kk) c[i]|=(1<<(j-1));
		}
	}
//	for(int i=1;i<=n;++i,printf("\n"))
//		for(int j=1;j<=n;++j)
//		if(c[i]&(1<<(j-1))) printf("1 ");
//		else printf("0 ");
	for(int i=1;i<=n;++i)
	f[i][0]=((1<<(n))-1);

	for(int i=1;i<=n;++i)
	for(int s=1;s<(1<<(n));++s)
	if(s&(1<<(i-1)))
	for(int j=1;j<=n;++j)
	if((s&(1<<(j-1))) and f[i][s^(1<<(j-1))]&c[j])
		f[i][s]|=(1<<(j-1));

	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<m;++k) ans=min(ans,abs(a[j][k]-a[i][k+1]));
			if(ans>=kk and (f[i][(1<<n)-1]&(1<<(j-1)))) return true;
		}
	}
	return false;
}
int find(int l,int r){
	if(l==r) return l;
	if(l+1==r){
		if(check(r)) return r;
		return l;
	}
	int mid=(l+r)/2;
	if(check(mid)) return find(mid,r);
	return find(l,mid-1);
}
int main(){
//	freopen("a.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	scanf("%d",&a[i][j]);
//	check(5);
	printf("%d\n",find(0,1e9));
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x7FFFFFFF
#define N 20
#define M 1100
using namespace std;
int a[N][M],n,m,f[N][1<<N],c[N];
inline bool check(int kk){
	memset(c,0,sizeof c);
	memset(f,0,sizeof f);

	for(int i=1;i<=n;++i) c[i]|=(1<<(i-1));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
//			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<=m;++k) ans=min(ans,abs(a[i][k]-a[j][k]));
			if(ans>=kk) c[i]|=(1<<(j-1));
		}
	}
//	for(int i=1;i<=n;++i,printf("\n"))
//		for(int j=1;j<=n;++j)
//		if(c[i]&(1<<(j-1))) printf("1 ");
//		else printf("0 ");
	for(int i=1;i<=n;++i)
	f[i][0]=((1<<(n))-1);

	for(int i=1;i<=n;++i)
	for(int s=1;s<(1<<(n));++s)
	if(s&(1<<(i-1)))
	for(int j=1;j<=n;++j)
	if((s&(1<<(j-1))) and f[i][s^(1<<(j-1))]&c[j])
		f[i][s]|=(1<<(j-1));

	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
//			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<m;++k) ans=min(ans,abs(a[j][k]-a[i][k+1]));
			if(ans>=kk and (f[i][(1<<n)-1]&(1<<(j-1)))) return true;
		}
	}
	return false;
}
int find(int l,int r){
	if(l==r) return l;
	if(l+1==r){
		if(check(r)) return r;
		return l;
	}
	int mid=(l+r)/2;
	if(check(mid)) return find(mid,r);
	return find(l,mid-1);
}
int main(){
//	freopen("a.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	scanf("%d",&a[i][j]);
//	check(5);
	printf("%d\n",find(0,1e9));
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x7FFFFFFF
#define N 20
#define M 11000
using namespace std;
int a[N][M],n,m,f[N][1<<N],c[N];
inline bool check(int kk){
	memset(c,0,sizeof c);
	memset(f,0,sizeof f);

	for(int i=1;i<=n;++i) c[i]|=(1<<(i-1));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
//			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<=m;++k) ans=min(ans,abs(a[i][k]-a[j][k]));
			if(ans>=kk) c[i]|=(1<<(j-1));
		}
	}
//	for(int i=1;i<=n;++i,printf("\n"))
//		for(int j=1;j<=n;++j)
//		if(c[i]&(1<<(j-1))) printf("1 ");
//		else printf("0 ");
	for(int i=1;i<=n;++i)
	f[i][0]=((1<<(n))-1);

	for(int i=1;i<=n;++i)
	for(int s=1;s<(1<<(n));++s)
	if(s&(1<<(i-1)))
	for(int j=1;j<=n;++j)
	if((s&(1<<(j-1))) and f[i][s^(1<<(j-1))]&c[j])
		f[i][s]|=(1<<(j-1));

	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
//			if(i==j) continue;
			int ans=inf;
			for(int k=1;k<m;++k) ans=min(ans,abs(a[j][k]-a[i][k+1]));
			if(ans>=kk and (f[i][(1<<n)-1]&(1<<(j-1)))) return true;
		}
	}
	return false;
}
int find(int l,int r){
	if(l==r) return l;
	if(l+1==r){
		if(check(r)) return r;
		return l;
	}
	int mid=(l+r)/2;
	if(check(mid)) return find(mid,r);
	return find(l,mid-1);
}
int main(){
//	freopen("a.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	scanf("%d",&a[i][j]);
//	check(5);
	printf("%d\n",find(0,1e9));
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define int long long

const int MAXN = 1e5 + 7;
const int INF = 1e16 + 7;

int n, m;
int a[MAXN], b[MAXN];

bool check(int want) {
    for (int i = 0; i < n; ++i) {
        b[i] = a[i];
    }
    int u = n - 1;
    while (b[u] == 0) {
        --u;
    }
    for (int i = 0; i < m; ++i) {
        int t = want - u - 1;
        while (1) {
            if (t < 0) {
                break;
            }
            else if (t >= b[u]) {
                t -= b[u];
                if (u == 0) {
                    return 1;
                }
                --u;
            }
            else {
                b[u] -= t;
                break;
            }
        }
    }
    return 0;
}

signed main() {
    #ifdef HOME
        freopen("input.txt", "r", stdin);
    #endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    int l = -1;
    int r = INF;
    while (l < r - 1) {
        int mid = (l + r) >> 1;
        if (check(mid)) {
            r = mid;
        }
        else {
            l = mid;
        }
    }

    cout << r << '\n';
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define int long long

const int MAXN = 1e5 + 7;
const int INF = 1e16 + 7;

int a[MAXN], b[MAXN];

bool check(int n, int m, int k) {
    for (int i = 0; i < n; ++i) {
        b[i] = a[i];
    }
    int u = n - 1;
    for (int i = 0; i < k; ++i) {
        int t = m - u - 1;
        while (1) {
            if (t < 0) {
                break;
            }
            else if (t >= b[u]) {
                t -= b[u];
                if (u == 0) {
                    return 1;
                }
                --u;
            }
            else {
                b[u] -= t;
                break;
            }
        }
    }
    return 0;
}

signed main() {
    #ifdef HOME
        freopen("input.txt", "r", stdin);
    #endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    int l = -1;
    int r = INF;
    while (l < r - 1) {
        int mid = (l + r) >> 1;
        if (check(n, mid, m)) {
            r = mid;
        }
        else {
            l = mid;
        }
    }

    cout << r << '\n';
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define int long long

const int MAXN = 1e5 + 7;
const int INF = 1e16 + 7;

int a[MAXN], b[MAXN];

bool check(int n, int m, int k) {
    for (int i = 0; i < n; ++i) {
        b[i] = a[i];
    }
    int u = n - 1;
    for (int i = 0; i < k; ++i) {
        int t = m - u - 1;
        while (1) {
            if (t >= b[u]) {
                t -= b[u];
                if (u == 0) {
                    return 1;
                }
                --u;
            }
            else {
                b[u] -= t;
                break;
            }
        }
    }
    return 0;
}

signed main() {
    #ifdef HOME
        freopen("input.txt", "r", stdin);
    #endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    int l = -1;
    int r = INF;
    while (l < r - 1) {
        int mid = (l + r) >> 1;
        if (check(n, mid, m)) {
            r = mid;
        }
        else {
            l = mid;
        }
    }

    cout << r << '\n';
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define int long long

const int MAXN = 1e5 + 7;
const int INF = 1e16 + 7;

int n, m;
int a[MAXN], b[MAXN];

bool check(int want) {
    for (int i = 0; i < n; ++i) {
        b[i] = a[i];
    }
    int u = n - 1;
    for (int i = 0; i < m; ++i) {
        int t = want - u - 1;
        while (1) {
            if (t < 0) {
                break;
            }
            else if (t >= b[u]) {
                t -= b[u];
                if (u == 0) {
                    return 1;
                }
                --u;
            }
            else {
                b[u] -= t;
                break;
            }
        }
    }
    return 0;
}

signed main() {
    #ifdef HOME
        freopen("input.txt", "r", stdin);
    #endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    int l = -1;
    int r = INF;
    while (l < r - 1) {
        int mid = (l + r) >> 1;
        if (check(mid)) {
            r = mid;
        }
        else {
            l = mid;
        }
    }

    cout << r << '\n';
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF (ll)1e14

const ll N = 123456;

ll a[N], n, m;

bool predicate(ll x) 	//check if piles can be cleared in x seconds
{
	int last;
	for (last = n; last >= 1; last--)
		if (a[last] != 0)
			break;

	int st = 1, i = 1, curr = 0, left = a[1];
	while (i <= last)
	{
		if (curr + left < x)
		{
			curr += a[i++] + 1;
			left = a[i];
		}
		else if (curr + left == x)
		{
			st++, i++;
			left = a[i];
			curr = i;
		}
		else
		{
			left -= (x - curr);
			st++;
			curr = i;
		}

		if (st > m)
			return 0;
	}

	return st <= m;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (int i = 1; i <= n; i++)
		cin>>a[i];

	ll low = 0, high = INF;
	while (low < high)
	{
		ll mid = low + (high - low)/2;
		if (predicate(mid))
			high = mid;
		else
			low = mid + 1;
	}
	cout<<low<<endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF (ll)1e14

const ll N = 123456;

ll a[N], n, m;

bool predicate(ll time_allowed)
{
	int last;
	for (last = n; last >= 1; last--)
		if (a[last] != 0)
			break;
	if (last == 0)
		return 1;

	int i = 1, st = 1, curr_time_spent = 1, curr_pile = a[1];
	while (i <= last)
	{
		// cout<<"time allowed = "<<time_allowed<<", i = "<<i<<", a[i] = "<<a[i]<<", curr_pile = "<<curr_pile<<", st = "<<st<<", curr_time_spent = "<<curr_time_spent<<endl;
		if (curr_pile == 0)
		{
			if (i == last)
				return (st <= m);
			i++;
			curr_pile = a[i];
			if (curr_time_spent == time_allowed)
				st++, curr_time_spent = i;
			else
				curr_time_spent++;
		}
		else
		{
			if ((time_allowed - curr_time_spent) >= curr_pile)
			{
				curr_time_spent += curr_pile;
				curr_pile = 0;
			}
			else
			{
				curr_pile -= (time_allowed - curr_time_spent);
				st++, curr_time_spent = i;
			}
		}

		if (st > m)
			return 0;
	}

	return st <= m;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (int i = 1; i <= n; i++)
		cin>>a[i];

	ll low = 0, high = INF;
	while (low < high)
	{
		ll mid = low + (high - low)/2;
		if (predicate(mid))
			high = mid;
		else
			low = mid + 1;
	}
	cout<<low<<endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF (ll)1e15

const ll N = 123456;

ll a[N], n, m;

bool predicate(ll time_allowed)
{
	ll last;
	for (last = n; last >= 1; last--)
		if (a[last] != 0)
			break;
	if (last == 0)
		return 1;

	ll i = 1, st = 1, curr_time_spent = 1, curr_pile = a[1];
	while (i <= last)
	{
		if (curr_pile == 0)
		{
			if (i == last)
				return (st <= m);
			i++;
			curr_pile = a[i];
			if (curr_time_spent == time_allowed)
				st++, curr_time_spent = i;
			else
				curr_time_spent++;
		}
		else
		{
			if ((time_allowed - curr_time_spent) >= curr_pile)
			{
				curr_time_spent += curr_pile;
				curr_pile = 0;
			}
			else
			{
				curr_pile -= (time_allowed - curr_time_spent);
				st++, curr_time_spent = i;
			}
		}

		if (st > m)
			return 0;
	}

	return st <= m;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (ll i = 1; i <= n; i++)
		cin>>a[i];

	ll low = 0, high = INF;
	while (low < high)
	{
		ll mid = low + (high - low)/2;
		if (predicate(mid))
			high = mid;
		else
			low = mid + 1;
	}
	cout<<low<<endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF (ll)1e14

const ll N = 123456;

ll a[N], n, m;

bool predicate(ll time_allowed)
{
	ll last;
	for (last = n; last >= 1; last--)
		if (a[last] != 0)
			break;
	if (last == 0)
		return 1;

	ll i = 1, st = 1, curr_time_spent = 1, curr_pile = a[1];
	while (i <= last)
	{
		if (curr_pile == 0)
		{
			if (i == last)
				return (st <= m);
			i++;
			curr_pile = a[i];
			if (curr_time_spent == time_allowed)
				st++, curr_time_spent = i;
			else
				curr_time_spent++;
		}
		else
		{
			if ((time_allowed - curr_time_spent) >= curr_pile)
			{
				curr_time_spent += curr_pile;
				curr_pile = 0;
			}
			else
			{
				curr_pile -= (time_allowed - curr_time_spent);
				st++, curr_time_spent = i;
			}
		}

		if (st > m)
			return 0;
	}

	return st <= m;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (ll i = 1; i <= n; i++)
		cin>>a[i];

	ll low = 0, high = INF;
	while (low < high)
	{
		ll mid = low + (high - low)/2;
		if (predicate(mid))
			high = mid;
		else
			low = mid + 1;
	}
	cout<<low<<endl;
	return 0;
}


/*input
4 100
3 4 5 4
*/
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF (ll)1e14

const ll N = 123456;

ll a[N], n, m;

bool predicate(ll time_allowed)
{
	int last;
	for (last = n; last >= 1; last--)
		if (a[last] != 0)
			break;
	if (last == 0)
		return 1;

	int i = 1, st = 1, curr_time_spent = 1, curr_pile = a[1];
	while (i <= last)
	{
		// cout<<"time allowed = "<<time_allowed<<", i = "<<i<<", a[i] = "<<a[i]<<", curr_pile = "<<curr_pile<<", st = "<<st<<", curr_time_spent = "<<curr_time_spent<<endl;
		if (curr_pile == 0)
		{
			i++;
			curr_pile = a[i];
			if (curr_time_spent == time_allowed)
				st++, curr_time_spent = i;
			else
				curr_time_spent++;
		}
		else
		{
			if ((time_allowed - curr_time_spent) >= curr_pile)
			{
				curr_time_spent += curr_pile;
				curr_pile = 0;
			}
			else
			{
				curr_pile -= (time_allowed - curr_time_spent);
				st++, curr_time_spent = i;
			}
		}

		if (st > m)
			return 0;
	}

	return st <= m;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (int i = 1; i <= n; i++)
		cin>>a[i];

	ll low = 0, high = INF;
	while (low < high)
	{
		ll mid = low + (high - low)/2;
		if (predicate(mid))
			high = mid;
		else
			low = mid + 1;
	}
	cout<<low<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 1e5 + 20;
ll a[N];

int main()
{
	int n, m;
	cin >> n >> m;
	ll maj = 0;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
		maj += a[i];
		maj++;
	}
	ll l = -1, r = maj;
	while (r - l > 1)
	{
		ll t = (l + r) / 2;
		maj = 0;
		int f = 1;
		ll bacheha = m;
		for (int i = n - 1; i > -1; i--)
		{
			if (a[i] == 0) continue;
			if (a[i] <= maj)
			{
				maj -= a[i];
				continue;
			}
			a[i] -= maj;
			maj = 0;
			if (t - i - 1 <= 0)
			{
				f = 0;
				break;
			}
			ll ted = a[i] / (t - i - 1);
			a[i] %= (t - i - 1);
			if (a[i] != 0)
			{
				ted++;
				maj += t - i - 1 - a[i];
			}
			if (ted > bacheha)
			{
				f = 0;
				break;
			}
			bacheha -= ted;
		}
		if (f)
		{
			r = t;
			continue;
		}
		l = t;
	}
	cout << r;
}


#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 1e5 + 20;
ll a[N];

int main()
{
	int n, m;
	cin >> n >> m;
	ll maj = 0;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
		maj += a[i];
		maj++;
	}
	ll l = -1, r = maj;
	while (r - l > 1)
	{
		ll t = (l + r) / 2;
		maj = 0;
		int f = 1;
		ll bacheha = m;
		for (int i = n - 1; i > -1; i--)
		{
			if (a[i] == 0) continue;
			if (a[i] <= maj)
			{
				maj -= a[i];
				continue;
			}
			ll num = a[i] - maj;
			maj = 0;
			if (t - i - 1 <= 0)
			{
				f = 0;
				break;
			}
			ll ted = num / (t - i - 1);
			num %= (t - i - 1);
			if (num != 0)
			{
				ted++;
				maj += t - i - 1 - num;
			}
			if (ted > bacheha)
			{
				f = 0;
				break;
			}
			bacheha -= ted;
		}
		if (f)
		{
			r = t;
			continue;
		}
		l = t;
	}
	cout << r;
}