//include
//------------------------------------------
#include <vector>
#include <list>
#include <map>
#include <climits>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <queue>
#include <random>
#include <cctype>
#include <complex>
#include <regex>
#include <unordered_map>

using namespace std;

//typedef
//------------------------------------------
typedef long long LL;
typedef vector<int> VI;
typedef vector<bool> VB;
typedef vector<char> VC;
typedef vector<double> VD;
typedef vector<string> VS;
typedef vector<LL> VLL;
typedef vector<VI> VVI;
typedef vector<VB> VVB;
typedef vector<VS> VVS;
typedef vector<VLL> VVLL;
typedef vector<VVI> VVVI;
typedef vector<VVLL> VVVLL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<int, string> PIS;
typedef pair<string, int> PSI;
typedef pair<string, string> PSS;
typedef vector<PII> VPII;
typedef vector<PLL> VPLL;
typedef vector<VPII> VVPII;
typedef vector<VPLL> VVPLL;
typedef vector<VS> VVS;

//数値・文字列
//------------------------------------------
inline int toInt(string s) {
    int v;
    istringstream sin(s);
    sin >> v;
    return v;
}

inline LL toLongLong(string s) {
    LL v;
    istringstream sin(s);
    sin >> v;
    return v;
}

template<class T>
inline string toString(T x) {
    ostringstream sout;
    sout << x;
    return sout.str();
}

inline VC toVC(string s) {
    VC data(s.begin(), s.end());
    return data;
}

template<typename List>
void SPRIT(const std::string &s, const std::string &delim, List &result) {
    result.clear();
    string::size_type pos = 0;
    while (pos != string::npos) {
        string::size_type p = s.find(delim, pos);
        if (p == string::npos) {
            result.push_back(s.substr(pos));
            break;
        } else {
            result.push_back(s.substr(pos, p - pos));
        }
        pos = p + delim.size();
    }
}

string TRIM(const string &str, const char *trimCharacterList = " \t\v\r\n") {
    string result;
    string::size_type left = str.find_first_not_of(trimCharacterList);
    if (left != string::npos) {
        string::size_type right = str.find_last_not_of(trimCharacterList);
        result = str.substr(left, right - left + 1);
    }
    return result;
}

string REPLACE_STRING(const string source, const string find, const string alt) {
    string result = source;
    string::size_type pos = 0;
    while (pos = result.find(find, pos), pos != string::npos) {
        result.replace(pos, find.length(), alt);
        pos += alt.length();
    }
    return result;
}

template<typename T>
bool VECTOR_EXISTS(vector<T> vec, T data) {
    auto itr = std::find(vec.begin(), vec.end(), data);
    size_t index = distance(vec.begin(), itr);
    if (index != vec.size())return true;
    else return false;
}

template<typename T>
vector<T> VECTOR_UNIQUE_ERASE(vector<T> vec) {
    sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end()), vec.end());
    return vec;
}

template<typename T>
void VECTOR_REMOVE_VALUE_ALL(vector<T> &vec, T data) {
    vec.erase(remove(vec.begin(), vec.end(), data), vec.end());
}

template<typename T>
vector<T> VECTOR_REMOVE_VALUE_ALL_FAST(vector<T> vec, T data) {
    vector<T> vec2;
    for (auto &x: vec) if (x != data) vec2.push_back(x);
    return vec2;
}

bool REG_MATCH(string const &text, regex const &re) {
    bool result = regex_match(text, re);
    return result;
}

bool REG_MATCH(string const &text, smatch &match, regex const &re) {
    bool result = regex_match(text, match, re);
    return result;
}

smatch REG_SEARCH(string const &text, regex const &re) {
    smatch m;
    regex_search(text, m, re);
    return m;
}

vector<smatch> REG_ALL_SEARCH(string const &text, regex const &re) {
    vector<smatch> matchs;
    sregex_iterator iter(text.cbegin(), text.cend(), re);
    sregex_iterator end;
    for (; iter != end; iter++) matchs.push_back(*iter);
    return matchs;
}

string REG_REPLACE(string const &text, regex const &re, string const &replace) {
    string result = regex_replace(text, re, replace, regex_constants::format_first_only);
    return result;
}

string REG_ALL_REPLACE(string const &text, regex const &re, string const &replace) {
    string result = regex_replace(text, re, replace);
    return result;
}

template<typename T, typename U, typename V, typename W>
auto operator+(const std::pair<T, U> &l, const std::pair<V, W> &r) -> std::pair<decltype(l.first + r.first), decltype(l.second + r.second)> {
    return {l.first + r.first, l.second + r.second};
}

template<typename T, typename U, typename V, typename W>
auto operator-(const std::pair<T, U> &l, const std::pair<V, W> &r) -> std::pair<decltype(l.first - r.first), decltype(l.second - r.second)> {
    return {l.first - r.first, l.second - r.second};
}

#define UPPER(s) transform((s).begin(), (s).end(), (s).begin(), ::toupper)
#define LOWER(s) transform((s).begin(), (s).end(), (s).begin(), ::tolower)

//四捨五入 nLen=小数点第n位にする
//------------------------------------------

//切り上げ
double ceil_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut + 0.9);
    return dOut * pow(10.0, -nLen);
}

//切り捨て
double floor_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut);
    return dOut * pow(10.0, -nLen);
}

//四捨五入
double round_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut + 0.5);
    return dOut * pow(10.0, -nLen);
}

//n桁目の数の取得
int take_a_n(LL num, int n) {
    string str = toString(num);
    return str[str.length() - n] - '0';
}

//進数
//------------------------------------------

//"1111011" → 123
int strbase_2to10(const std::string &s) {
    int out = 0;
    for (int i = 0, size = s.size(); i < size; ++i) {
        out *= 2;
        out += ((int) s[i] == 49) ? 1 : 0;
    }
    return out;
}

//"123" → 1111011
int strbase_10to2(const std::string &s) {
    int binary = toInt(s);
    int out = 0;
    for (int i = 0; binary > 0; i++) {
        out = out + (binary % 2) * pow(static_cast<int>(10), i);
        binary = binary / 2;
    }
    return out;
}

//"ABC" 2748
int strbase_16to10(const std::string &s) {
    int out = stoi(s, 0, 16);
    return out;
}

//1111011 → 123
int intbase_2to10(int in) {
    string str = toString(in);
    return strbase_2to10(str);
}

//123 → 1111011
int intbase_10to2(int in) {
    string str = toString(in);
    return strbase_10to2(str);
}

int intbase_16to10(int in) {
    string str = toString(in);
    return strbase_16to10(str);
}

//123→ "7B"
string intbase_10to16(unsigned int val, bool lower = true) {
    if (!val)
        return std::string("0");
    std::string str;
    const char hc = lower ? 'a' : 'A';     // 小文字 or 大文字表記
    while (val != 0) {
        int d = val & 15;     // 16進数一桁を取得
        if (d < 10)
            str.insert(str.begin(), d + '0');  //  10未満の場合
        else //  10以上の場合
            str.insert(str.begin(), d - 10 + hc);
        val >>= 4;
    }
    return str;
}

//整数を2進数表記したときの1の個数を返す
LL bitcount64(LL bits) {
    bits = (bits & 0x5555555555555555) + (bits >> 1 & 0x5555555555555555);
    bits = (bits & 0x3333333333333333) + (bits >> 2 & 0x3333333333333333);
    bits = (bits & 0x0f0f0f0f0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f0f0f0f0f);
    bits = (bits & 0x00ff00ff00ff00ff) + (bits >> 8 & 0x00ff00ff00ff00ff);
    bits = (bits & 0x0000ffff0000ffff) + (bits >> 16 & 0x0000ffff0000ffff);
    return (bits & 0x00000000ffffffff) + (bits >> 32 & 0x00000000ffffffff);
}

//comparison
//------------------------------------------
#define C_MAX(a, b) ((a)>(b)?(a):(b))
#define C_MIN(a, b) ((a)<(b)?(a):(b))
#define C_ABS(a, b) ((a)<(b)?(b)-(a):(a)-(b))

template<typename T1, typename T2>
inline void S_MAX(T1 &a, T2 b) { a = C_MAX(a, b); };

template<typename T1, typename T2>
inline void S_MIN(T1 &a, T2 b) { a = C_MIN(a, b); };

//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define SZ(a) int((a).size())
#define EACH(i, arr) for(typeof((arr).begin()) i=(arr).begin(); i!=(arr).end(); ++i)
#define EXIST(str, e) ((str).find(e)!=(str).end())
#define COUNT(arr, v) count((arr).begin(), (arr).end(), v)
#define SEARCH(v, w) search((v).begin(), (v).end(), (w).begin(), (w).end())
#define B_SEARCH(arr, v) binary_search((arr).begin(), (arr).end(), v)
#define SORT(c) sort((c).begin(),(c).end())
#define RSORT(c) sort((c).rbegin(),(c).rend())
#define REVERSE(c) reverse((c).begin(), (c).end())
#define ROTATE_LEFT(arr, c) rotate((arr).begin(), (arr).begin()+(c), (arr).end())
#define ROTATE_RIGHT(arr, c) rotate((arr).rbegin(), (arr).rbegin() + (c), (arr).rend())
#define SUMI(arr) accumulate((arr).begin(), (arr).end(), 0)
#define SUMD(arr) accumulate((arr).begin(), (arr).end(), 0.)
#define SUMLL(arr) accumulate((arr).begin(), (arr).end(), 0LL)
#define SUMS(arr) accumulate((arr).begin(), (arr).end(), string())
#define UB(arr, n) upper_bound((arr).begin(), (arr).end(), n)
#define LB(arr, n) lower_bound((arr).begin(), (arr).end(), n)
#define OF_ALL(arr, func) all_of((arr).begin(), (arr).end(), (func))
#define OF_NONE(arr, func) none_of((arr).begin(), (arr).end(), (func))
#define OF_ANY(arr, func) any_of((arr).begin(), (arr).end(), (func))
#define PB push_back
#define MP make_pair

//input output
//------------------------------------------
#define GL(s) getline(cin, (s))
#define INIT() std::ios::sync_with_stdio(false);std::cin.tie(0);
#define OUT(d) std::cout<<(d)
#define OUT_L(d) std::cout<<(d)<<endl
#define FOUT(n, data) std::cout<<std::fixed<<std::setprecision(n)<<(data)
#define FOUT_L(n, data) std::cout<<std::fixed<<std::setprecision(n)<<(data)<<"\n"
#define EL() printf("\n")
#define SHOW_VECTOR(v) {std::cerr << #v << "\t:";for(const auto& xxx : v){std::cerr << xxx << " ";}std::cerr << "\n";}
#define SHOW_MAP(v) {std::cerr << #v << endl; for(const auto& xxx: v){std::cerr << xxx.first << " " << xxx.second << "\n";}}
#define Yes() printf("Yes\n")
#define No() printf("No\n")
#define YES() printf("YES\n")
#define NO() printf("NO\n")

template<typename T1, typename T2>
istream &operator>>(istream &in, pair<T1, T2> &p) {
    in >> p.first >> p.second;
    return in;
}

template<typename T>
istream &operator>>(istream &in, vector<T> &v) {
    for (auto &x: v)
        in >> x;
    return in;
}

//repetition
//------------------------------------------
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RFOR(i, a, b) for(int i=(b)-1;i>=(a);--i)
#define REP(i, n)  FOR(i,0,n)
#define RREP(i, n) for(int i = n-1;i >= 0;i--)
#define FORLL(i, a, b) for(LL i=LL(a);i<LL(b);++i)
#define RFORLL(i, a, b) for(LL i=LL(b)-1;i>=LL(a);--i)
#define REPLL(i, n) for(LL i=0;i<LL(n);++i)
#define RREPLL(i, n) for(LL i=LL(n)-1;i>=0;--i)
#define FOREACH(x, arr) for(auto &(x) : (arr))
#define FORITER(x, arr) for(auto (x) = (arr).begin(); (x) != (arr).end(); ++(x))

//constant
//--------------------------------------------
const double EPS = 1e-10;
const double PI = acos(-1.0);
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};

//math
//--------------------------------------------

//min <= aim <= max
template<typename T>
inline bool BETWEEN(const T aim, const T min, const T max) {
    if (min <= aim && aim <= max) {
        return true;
    } else {
        return false;
    }
}

template<class T>
inline T SQR(const T x) { return x * x; }

template<class T1, class T2>
inline T1 POW(const T1 x, const T2 y) {
    if (!y)return 1;
    else if ((y & 1) == 0) {
        return SQR(POW(x, y >> 1));
    } else return POW(x, y ^ 1) * x;
}

template<typename T>
constexpr T ABS(T x) {
    return x < 0 ? -x : x;
}

//partial_permutation nPr 順列
//first・・最初の数
//middle・・r(取り出す数)
//last・・n(全体数)
template<class Iter>
bool next_partial_permutation(Iter first, Iter middle, Iter last) {
    reverse(middle, last);
    return next_permutation(first, last);
}

//combination nCr 組み合わせ
//first1・・最初の数
//last1==first2・・r(取り出す数)
//last2・・n(全体数)
template<class Iter>
bool next_combination(Iter first1, Iter last1, Iter first2,
                      Iter last2) {
    if ((first1 == last1) || (first2 == last2)) {
        return false;
    }
    Iter m1 = last1;
    Iter m2 = last2;
    --m2;
    while (--m1 != first1 && !(*m1 < *m2)) {
    }
    bool result = (m1 == first1) && !(*first1 < *m2);
    if (!result) {
        while (first2 != m2 && !(*m1 < *first2)) {
            ++first2;
        }
        first1 = m1;
        std::iter_swap(first1, first2);
        ++first1;
        ++first2;
    }
    if ((first1 != last1) && (first2 != last2)) {
        m1 = last1;
        m2 = first2;
        while ((m1 != first1) && (m2 != last2)) {
            std::iter_swap(--m1, m2);
            ++m2;
        }
        std::reverse(first1, m1);
        std::reverse(first1, last1);
        std::reverse(m2, last2);
        std::reverse(first2, last2);
    }
    return !result;
}

//numeric_law
//--------------------------------------------

template<typename T>
constexpr bool ODD(T x) {
    return x % 2 != 0;
}

template<typename T>
constexpr bool EVEN(T x) {
    return x % 2 == 0;
}

//最大公約数
template<class T>
inline T GCD(const T x, const T y) {
    if (x < 0)return GCD(-x, y);
    if (y < 0)return GCD(x, -y);
    return (!y) ? x : GCD(y, x % y);
}

//最小公倍数
template<class T>
inline T LCM(const T x, const T y) {
    if (x < 0)return LCM(-x, y);
    if (y < 0)return LCM(x, -y);
    return x * (y / GCD(x, y));
}

//ax + by = 1
//x,yが変数に格納される
template<class T>
inline T EXTGCD(const T a, const T b, T &x, T &y) {
    if (a < 0) {
        T d = EXTGCD(-a, b, x, y);
        x = -x;
        return d;
    }
    if (b < 0) {
        T d = EXTGCD(a, -b, x, y);
        y = -y;
        return d;
    }
    if (!b) {
        x = 1;
        y = 0;
        return a;
    } else {
        T d = EXTGCD(b, a % b, x, y);
        T t = x;
        x = y;
        y = t - (a / b) * y;
        return d;
    }
}

//素数
template<class T>
inline bool ISPRIME(const T x) {
    if (x <= 1)return false;
    for (T i = 2; SQR(i) <= x; i++)if (x % i == 0)return false;
    return true;
}

//素数をtrueとして返す
template<class T>
VB ERATOSTHENES(const T n) {
    VB arr(n, true);
    for (int i = 2; SQR(i) < n; i++) {
        if (arr[i]) {
            for (int j = 0; i * (j + 2) < n; j++) {
                arr[i * (j + 2)] = false;
            }
        }
    }
    return arr;
}

// a <= x < b の素数を返す
template<typename T>
VB ERATOSTHENES(const T a, const T b) {
    VB small = ERATOSTHENES(b);
    VB prime(b - a, true);

    for (int i = 2; (T) (SQR(i)) < b; i++) {
        if (small[i]) {
            for (T j = max(2, (a + i - 1) / i) * i; j < b; j += i) {
                prime[j - a] = false;
            }
        }
    }

    return prime;
}

//nの約数
template<typename T>
vector<T> DIVISOR(T n) {
    vector<T> v;
    for (LL i = 1; i * i <= n; ++i) {
        if (n % i == 0) {
            v.push_back(i);
            if (i != n / i) {
                v.push_back(n / i);
            }
        }
    }
    sort(v.begin(), v.end());
    return v;
}

//nまでのすべての約数
template<typename T>
vector<vector<T>> DIVISOR_ALL(T n) {
    vector<vector<T>> res(n + 1);
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j += i) {
            res[j].push_back(i);
        }
    }
    return res;
}

//素因数分解
template<typename T>
vector<pair<T, LL>> FACTORIZATION(T x) {
    vector<pair<T, LL>> ans;
    for (T i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            LL count = 0;
            while (x % i == 0) {
                count++;
                x /= i;
            }
            ans.push_back(MP(i, count));
        }
    }
    if (x != 1) ans.push_back(MP(x, 1));
    return ans;
}

//N^P (mod M)
LL POW_MOD(LL N, LL P, LL M) {
    if (P == 0) return 1LL;
    if (P % 2 == 0) {
        LL ret = POW_MOD(N, P / 2, M);
        return ret * ret % M;
    }
    return N * POW_MOD(N, P - 1, M) % M;
}

//組み合わせ個数
template<typename T>
inline T NCR(T n, T r) {
    T ans = 1;
    REPLL(i, r) {
        ans = ans * (n - i) / (i + 1);
    }
    return ans;
}

//組み合わせ個数 (mod M)
LL NCR_MOD(LL n, LL r, LL M) {
    if (r > n - r) return NCR_MOD(n, n - r, M);
    LL numerator = 1LL; //分子
    LL denominator = 1LL; //分母
    for (LL i = 0; i < r; i++) {
        numerator *= (n - i);
        numerator %= M;
        denominator *= (i + 1);
        denominator %= M;
    }
    return numerator * POW_MOD(denominator, M - 2, M) % M;
}

//confirmation
//--------------------------------------------

//clear memory
#define CLR(arr, d) memset((arr), (d),sizeof(arr))

//debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;

/*
 *
 *
 *   ~~~~Below My Answer~~~~
 *
 *
 */

constexpr long long INF = 1e12;

vector<vector<long long>> dp;

long long f(long long v, long long S, int N, int M, vector<vector<long long>> &a, long long first) {
    if (dp[S][v] != INF)return dp[S][v];
    if (S == ((1 << N) - 1)) {
        long long maxV = INF;
        for (int i = 0; i < M - 1; i++) {
            maxV = min(maxV, abs(a[first][i] - a[v][i + 1]));
        }
        return dp[S][v] = maxV;
    }
    long long ret = 0;
    for (int i = 0; i < N; i++) {
        if (!(S & (1 << i))) {
            int toS = S | (1 << i);
            long long maxV = INF;
            for (int j = 0; j < M; j++) maxV = min(maxV, abs(a[i][j] - a[v][j]));
            ret = max(ret, min(maxV, f(i, toS, N, M, a, first)));
        }
    }
    return dp[S][v] = ret;
}

int main() {

    int N, M;
    cin >> N >> M;

    vector<vector<long long>> a(N, vector<long long>(M));
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
            cin >> a[i][j];

    //
    long long ans = 0;
    for (int i = 0; i < N; i++) {
        dp = vector<vector<long long>>(1 << N, vector<long long>(N, INF));
        ans = max(ans, f(i, 1 << i, N, M, a, i));
    }

    cout << ans << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int M=2e5+7;
const ll q=7057594037927903;
const ll prime=2137;
#define pb push_back
#define mp make_pair
#define f first
#define s second

int n,m,tab[18][10007],dp[18][(1<<17)+20][18],zmienna,wynik,potegi[25],policz[25][25],wazne;
vector <int>v[M];

int nxt_int()
{
    char c;
    do{c=_getchar_nolock();}while(!isdigit(c));
    int result=c-'0';
    while(isdigit(c=_getchar_nolock()))
      result=result*10+c-'0';

    return result;
}

void wczytaj()
{
   scanf("%d%d",&n,&m);
   for(int i=0; i<n; i++)
     for(int j=1; j<=m; j++)
        tab[i][j]=nxt_int();
}

void zamien_wiersze(int a)
{
   for(int j=1; j<=m; j++)
     swap(tab[0][j],tab[a][j]);

   for(int i=0; i<n; i++)
   {
      wazne=INT_MAX;
      for(int k=1; k<=m; k++)
        wazne=min(wazne,abs(tab[0][k]-tab[i][k]));
      policz[0][i]=wazne;
      policz[i][0]=wazne;
   }

   for(int i=0; i<n; i++)
   {
      wazne=INT_MAX;
      for(int k=1; k<=m; k++)
        wazne=min(wazne,abs(tab[a][k]-tab[i][k]));
      policz[a][i]=wazne;
      policz[i][a]=wazne;
   }
}

void policzor()
{
    for(int i=0; i<n; i++)
       for(int j=0; j<n; j++)
       {
          wazne=INT_MAX;
          for(int k=1; k<=m; k++)
            wazne=min(wazne,abs(tab[i][k]-tab[j][k]));
          policz[i][j]=wazne;
       }
}

int policz2(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<m; j++)
      wazne=min(wazne,abs(tab[b][j]-tab[a][j+1]));

   return wazne;
}

void rozklad()
{
    potegi[0]=1;
    for(int j=1; j<=20; j++)
       potegi[j]=potegi[j-1]*2;

    for(int i=1; i<=zmienna+7; i++)
      for(int j=1; j<=17; j++)
        if(i&potegi[j])
          v[i].pb(j);
}

int main()
{
   wczytaj();
   zmienna=(1<<n)-1;
   rozklad();
   policzor();

   if(n==1)
   {
      printf("%d\n",policz2(0,0));
      return 0;
   }

   for(int i=0; i<=n-1; i++)
   {
      zamien_wiersze(i);
      for(int j=1; j<=zmienna; j++)
      {
          if(v[j].size()>=2)
          {
            for(int h=0; h<(int)v[j].size(); h++)
              for(int z=0; z<(int)v[j].size(); z++)
                 if(h!=z)
                 {
                    int pom=min(policz[v[j][h]][v[j][z]],dp[i][j^(potegi[v[j][h]])][v[j][z]]);
                    dp[i][j][v[j][h]]=max(dp[i][j][v[j][h]],pom);
                 }
           }
           else if(v[j].size()==1)
              dp[i][j][v[j][0]]=policz[0][v[j][0]];
      }

      for(int j=1; j<=n-1; j++)
        dp[i][zmienna][j]=min(dp[i][zmienna][j],policz2(0,j));

      for(int j=1; j<=n-1; j++)
         wynik=max(wynik,dp[i][zmienna][j]);
   }

   printf("%d\n",wynik);

   return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int M=2e5+7;
const ll q=7057594037927903;
const ll prime=2137;
#define pb push_back
#define mp make_pair
#define f first
#define s second

int n,m,tab[18][10007],dp[17][(1<<17)+20][17],zmienna,wynik,potegi[20];
vector <int>v[M];

void wczytaj()
{
   scanf("%d%d",&n,&m);
   for(int i=0; i<n; i++)
     for(int j=1; j<=m; j++)
        scanf("%d",&tab[i][j]);
}

void zamien_wiersze(int a)
{
   for(int j=1; j<=m; j++)
     swap(tab[0][j],tab[a][j]);
}

int policz(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<=m; j++)
     wazne=min(wazne,abs(tab[a][j]-tab[b][j]));

   return wazne;
}

int policz2(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<m; j++)
      wazne=min(wazne,abs(tab[b][j]-tab[a][j+1]));

   return wazne;
}

void rozklad()
{
    potegi[0]=1;
    for(int j=1; j<=20; j++)
       potegi[j]=potegi[j-1]*2;

    for(int i=1; i<=zmienna+7; i++)
      for(int j=1; j<=17; j++)
        if(i&potegi[j])
          v[i].pb(j);
}

int main()
{
   wczytaj();
   zmienna=(1<<n)-1;
   rozklad();

   if(n==1)
   {
      printf("%d\n",policz2(0,0));
      return 0;
   }

   for(int i=0; i<=n-1; i++)
   {
      zamien_wiersze(i);
      for(int j=1; j<=zmienna; j++)
      {
          if(v[j].size()>=2)
          {
            for(int h=0; h<(int)v[j].size(); h++)
              for(int z=0; z<(int)v[j].size(); z++)
                 if(h!=z)
                 {
                    int pom=min(policz(v[j][h],v[j][z]),dp[i][j^(potegi[v[j][h]])][v[j][z]]);
                    dp[i][j][v[j][h]]=max(dp[i][j][v[j][h]],pom);
                 }
           }
           else if(v[j].size()==1)
              dp[i][j][v[j][0]]=policz(0,v[j][0]);
      }

      for(int j=1; j<=n-1; j++)
        dp[i][zmienna][j]=min(dp[i][zmienna][j],policz2(0,j));

      for(int j=1; j<=n-1; j++)
         wynik=max(wynik,dp[i][zmienna][j]);
   }

   printf("%d\n",wynik);

   return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int M=2e5+7;
const ll q=7057594037927903;
const ll prime=2137;
#define pb push_back
#define mp make_pair
#define f first
#define s second

int n,m,tab[18][10007],dp[18][(1<<17)+20][18],zmienna,wynik,potegi[25],policz[25][25],wazne;
vector <int>v[M];

int nxt_int()
{
    char c;
    do{c=_getchar_nolock();}while(!isdigit(c));
    int result=c-'0';
    while(isdigit(c=_getchar_nolock()))
      result=result*10+c-'0';

    return result;
}

void wczytaj()
{
   scanf("%d%d",&n,&m);
   for(int i=0; i<n; i++)
     for(int j=1; j<=m; j++)
        tab[i][j]=nxt_int();
}

void zamien_wiersze(int a)
{
   for(int j=1; j<=m; j++)
     swap(tab[0][j],tab[a][j]);
}

void policzor()
{
    for(int i=0; i<n; i++)
       for(int j=0; j<n; j++)
       {
          wazne=INT_MAX;
          for(int k=1; k<=m; k++)
            wazne=min(wazne,abs(tab[i][k]-tab[j][k]));
          policz[i][j]=wazne;
       }
}

int policz2(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<m; j++)
      wazne=min(wazne,abs(tab[b][j]-tab[a][j+1]));

   return wazne;
}

void rozklad()
{
    potegi[0]=1;
    for(int j=1; j<=20; j++)
       potegi[j]=potegi[j-1]*2;

    for(int i=1; i<=zmienna+7; i++)
      for(int j=1; j<=17; j++)
        if(i&potegi[j])
          v[i].pb(j);
}

int main()
{
   wczytaj();
   zmienna=(1<<n)-1;
   rozklad();
   policzor();

   if(n==1)
   {
      printf("%d\n",policz2(0,0));
      return 0;
   }

   for(int i=0; i<=n-1; i++)
   {
      zamien_wiersze(i);
      for(int j=1; j<=zmienna; j++)
      {
          if(v[j].size()>=2)
          {
            for(int h=0; h<(int)v[j].size(); h++)
              for(int z=0; z<(int)v[j].size(); z++)
                 if(h!=z)
                 {
                    int pom=min(policz[v[j][h]][v[j][z]],dp[i][j^(potegi[v[j][h]])][v[j][z]]);
                    dp[i][j][v[j][h]]=max(dp[i][j][v[j][h]],pom);
                 }
           }
           else if(v[j].size()==1)
              dp[i][j][v[j][0]]=policz[0][v[j][0]];
      }

      for(int j=1; j<=n-1; j++)
        dp[i][zmienna][j]=min(dp[i][zmienna][j],policz2(0,j));

      for(int j=1; j<=n-1; j++)
         wynik=max(wynik,dp[i][zmienna][j]);
   }

   printf("%d\n",wynik);

   return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int M=2e5+7;
const ll q=7057594037927903;
const ll prime=2137;
#define pb push_back
#define mp make_pair
#define f first
#define s second

int n,m,tab[20][10007],dp[20][(1<<17)+20][20],zmienna,wynik,potegi[25];
vector <int>v[M];

int nxt_int()
{
    char c;
    do{c=_getchar_nolock();}while(!isdigit(c));
    int result=c-'0';
    while(isdigit(c=_getchar_nolock()))
      result=result*10+c-'0';

    return result;
}

void wczytaj()
{
   scanf("%d%d",&n,&m);
   for(int i=0; i<n; i++)
     for(int j=1; j<=m; j++)
         tab[i][j]=nxt_int();
}

void zamien_wiersze(int a)
{
   for(int j=1; j<=m; j++)
     swap(tab[0][j],tab[a][j]);
}

int policz(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<=m; j++)
     wazne=min(wazne,abs(tab[a][j]-tab[b][j]));

   return wazne;
}

int policz2(int a,int b)
{
   int wazne=INT_MAX;
   for(int j=1; j<m; j++)
      wazne=min(wazne,abs(tab[b][j]-tab[a][j+1]));

   return wazne;
}

void rozklad()
{
    potegi[0]=1;
    for(int j=1; j<=20; j++)
       potegi[j]=potegi[j-1]*2;

    for(int i=1; i<=zmienna+7; i++)
      for(int j=1; j<=17; j++)
        if(i&potegi[j])
          v[i].pb(j);
}

int main()
{
   wczytaj();
   zmienna=(1<<n)-1;
   rozklad();

   if(n==1)
   {
      printf("%d\n",policz2(0,0));
      return 0;
   }

   for(int i=0; i<=n-1; i++)
   {
      zamien_wiersze(i);
      for(int j=1; j<=zmienna; j++)
      {
          if(v[j].size()>=2)
          {
            for(int h=0; h<(int)v[j].size(); h++)
              for(int z=0; z<(int)v[j].size(); z++)
                 if(h!=z)
                 {
                    int pom=min(policz(v[j][h],v[j][z]),dp[i][j^(potegi[v[j][h]])][v[j][z]]);
                    dp[i][j][v[j][h]]=max(dp[i][j][v[j][h]],pom);
                 }
           }
           else if(v[j].size()==1)
              dp[i][j][v[j][0]]=policz(0,v[j][0]);
      }

      for(int j=1; j<=n-1; j++)
        dp[i][zmienna][j]=min(dp[i][zmienna][j],policz2(0,j));

      for(int j=1; j<=n-1; j++)
         wynik=max(wynik,dp[i][zmienna][j]);
   }

   printf("%d\n",wynik);

   return 0;
}


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {

           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               //((i&(1<<t))==1)||t==s
               if(s == t || (i>>t&1)==1) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cfloat>
#include <climits>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <bitset>
#include <sstream>
using namespace std;

#define LL long long
const int maxn = 16;
const int maxm = 10000 + 100;
int n, m;
int num[maxn][maxm];
int dp[maxn][maxn][1 << maxn];
int dis[maxn][maxn], dis_next[maxn][maxn];

int main()
{
#ifdef Dmaxiya
    freopen("test.txt", "r", stdin);
#endif // Dmaxiya
    ios::sync_with_stdio(false);

    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < m; ++j)
            {
                scanf("%d", &num[i][j]);
            }
        }
        if(n == 1)
        {
            int ans = INT_MAX;
            for(int i = 1; i < m; ++i)
            {
                ans = min(ans, abs(num[0][i] - num[0][i - 1]));
            }
            printf("%d\n", ans);
            continue;
        }
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                dis[i][j] = INT_MAX;
                dis_next[i][j] = INT_MAX;
                if(i == j)
                {
                    continue;
                }
                for(int k = 0; k < m; ++k)
                {
                    dis[i][j] = min(dis[i][j], abs(num[i][k] - num[j][k]));
                    if(k != 0)
                    {
                        dis_next[i][j] = min(dis_next[i][j], abs(num[i][k - 1] - num[j][k]));
                    }
                }
            }
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; ++i)
        {
            dp[i][i][1 << i] = INT_MAX;
        }
        for(int i = 1; i < (1 << n); ++i)
        {
            for(int s = 0; s < n; ++s)
            {
                if((i&(1<<s))==0)continue;
                for(int t = 0; t < n; ++t)
                {
                    if((i&(1<<t))==1||t==s)continue;
                    for(int e = 0; e < n; ++e)
                    {
                        if((i&(1<<e)) == 0)continue;
                        int tmp = i | (1 << t);
                        dp[s][t][tmp] = max(dp[s][t][tmp], min(dp[s][e][i], dis[e][t]));
                    }
                }
            }
        }
        int ans = 0;
        int tmp = (1 << n) - 1;
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(i == j) continue;
                ans = max(ans, min(dp[i][j][tmp], dis_next[j][i]));
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {

           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               //((i&(1<<t))==1)||t==s
               if(s == t || ((i&(1<<t))==1)) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    memset(dis_next,0x3f,sizeof(dis_next));
    memset(dis,0x3f,sizeof(dis));
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=inf;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }

    for(int i=0;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {
           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               if((i&(1<<t))==1||t==s) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cfloat>
#include <climits>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <bitset>
#include <sstream>
using namespace std;

#define LL long long
const int maxn = 16;
const int maxm = 10000 + 100;
int n, m;
int num[maxn][maxm];
int dp[maxn][maxn][1 << maxn];
int dis[maxn][maxn], dis_next[maxn][maxn];

int main()
{
#ifdef Dmaxiya
    freopen("test.txt", "r", stdin);
#endif // Dmaxiya
    ios::sync_with_stdio(false);

    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < m; ++j)
            {
                scanf("%d", &num[i][j]);
            }
        }
        if(n == 1)
        {
            int ans = INT_MAX;
            for(int i = 1; i < m; ++i)
            {
                ans = min(ans, abs(num[0][i] - num[0][i - 1]));
            }
            printf("%d\n", ans);
            continue;
        }
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                dis[i][j] = INT_MAX;
                dis_next[i][j] = INT_MAX;
                if(i == j)
                {
                    continue;
                }
                for(int k = 0; k < m; ++k)
                {
                    dis[i][j] = min(dis[i][j], abs(num[i][k] - num[j][k]));
                    if(k != 0)
                    {
                        dis_next[i][j] = min(dis_next[i][j], abs(num[i][k - 1] - num[j][k]));
                    }
                }
            }
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; ++i)
        {
            dp[i][i][1 << i] = INT_MAX;
        }
        for(int i = 1; i < (1 << n); ++i)
        {
            for(int s = 0; s < n; ++s)
            {
                if(((i >> s) & 1) == 0)
                {
                    continue;
                }
                for(int t = 0; t < n; ++t)
                {
                    if(s == t || ((i >> t) & 1) == 1)
                    {
                        continue;
                    }
                    for(int e = 0; e < n; ++e)
                    {
                        if(((i >> e) & 1) == 0)
                        {
                            continue;
                        }
                        int tmp = i | (1 << t);
                        dp[s][t][tmp] = max(dp[s][t][tmp], min(dp[s][e][i], dis[e][t]));
                    }
                }
            }
        }
        int ans = 0;
        int tmp = (1 << n) - 1;
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(i == j)
                {
                    continue;
                }
                ans = max(ans, min(dp[i][j][tmp], dis_next[j][i]));
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {

           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               //((i&(1<<t))==1)||t==s
               if(s == t || ((i>>t)&1)==1||((i&(1<<t))==1)) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cfloat>
#include <climits>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <bitset>
#include <sstream>
using namespace std;

#define LL long long
const int maxn = 16;
const int maxm = 10000 + 100;
int n, m;
int num[maxn][maxm];
int dp[maxn][maxn][1 << maxn];
int dis[maxn][maxn], dis_next[maxn][maxn];

int main()
{
#ifdef Dmaxiya
    freopen("test.txt", "r", stdin);
#endif // Dmaxiya
    ios::sync_with_stdio(false);

    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < m; ++j)
            {
                scanf("%d", &num[i][j]);
            }
        }
        if(n == 1)
        {
            int ans = INT_MAX;
            for(int i = 1; i < m; ++i)
            {
                ans = min(ans, abs(num[0][i] - num[0][i - 1]));
            }
            printf("%d\n", ans);
            continue;
        }
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                dis[i][j] = INT_MAX;
                dis_next[i][j] = INT_MAX;
                if(i == j)
                {
                    continue;
                }
                for(int k = 0; k < m; ++k)
                {
                    dis[i][j] = min(dis[i][j], abs(num[i][k] - num[j][k]));
                    if(k != 0)
                    {
                        dis_next[i][j] = min(dis_next[i][j], abs(num[i][k - 1] - num[j][k]));
                    }
                }
            }
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; ++i)
        {
            dp[i][i][1 << i] = INT_MAX;
        }
        for(int i = 1; i < (1 << n); ++i)
        {
            for(int s = 0; s < n; ++s)
            {
                if(((i >> s) & 1) == 0)
                {
                    continue;
                }
                for(int t = 0; t < n; ++t)
                {
                    if(s == t || ((i >> t) & 1) == 1)
                    {
                        continue;
                    }
                    for(int e = 0; e < n; ++j)
                    {
                        if(((i >> e) & 1) == 0)
                        {
                            continue;
                        }
                        int tmp = i | (1 << t);
                        dp[s][t][tmp] = max(dp[s][t][tmp], min(dp[s][e][i], dis[e][t]));
                    }
                }
            }
        }
        int ans = 0;
        int tmp = (1 << n) - 1;
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(i == j)
                {
                    continue;
                }
                ans = max(ans, min(dp[i][j][tmp], dis_next[j][i]));
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {

           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               if(s == t || ((i >> t) & 1) == 1) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=0;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {
           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               if((i&(1<<t))==1||t==s) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {

           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               //(i&(1<<t))==1||t==s
               if(s == t ||(i&(1<<t))==1) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[0][i]-mp[0][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            dis[i][j] = INT_MAX;
            dis_next[i][j] = INT_MAX;
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=INT_MAX;
    for(int i=1;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {
           if(((i >> s) & 1) == 0) continue;
           for(int t=0;t<n;t++)
           {
               if(s == t || ((i >> t) & 1) == 1) continue;
                for(int e=0;e<n;e++)
                {
                    if(((i >> e) & 1) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#include <set>
#include <map>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define debug(a,b) cout<<a<<" "<<b<<endl;
using namespace std;
const int N=1e4+10;
const int MOD=998244353;
int dis[20][20],mp[20][N],dp[20][20][1<<16],dis_next[20][20];
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",&mp[i][j]);
        }
    }
    if(n==1)
    {
        int ans=inf;
        for(int i=1;i<m;i++) ans=min(ans,abs(mp[1][i]-mp[1][i-1]));
        cout<<ans<<endl;
        return 0;
    }
    memset(dis_next,0x3f,sizeof(dis_next));
    memset(dis,0x3f,sizeof(dis));
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++) dp[i][i][1<<i]=inf;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            for(int k=0;k<m;k++)
            {
                dis[i][j] = min(dis[i][j], abs(mp[i][k] - mp[j][k]));
                if(k != 0)
                    dis_next[i][j] = min(dis_next[i][j], abs(mp[i][k - 1] - mp[j][k]));
            }
        }
    }

    for(int i=0;i<(1<<n);i++)
    {
        for(int s=0;s<n;s++)
        {
           if((i&(1<<s))==0) continue;
           for(int t=0;t<n;t++)
           {
               if((i&(1<<t))==1||t==s) continue;
                for(int e=0;e<n;e++)
                {
                    if((i&(1<<e)) == 0) continue;
                    dp[s][t][i|(1<<t)]=max(dp[s][t][i|(1<<t)],min(dp[s][e][i],dis[e][t]));
                }
           }

        }
    }
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            ans = max(ans, min(dp[i][j][(1<<n)-1], dis_next[j][i]));
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
2500000000
*/


#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int i, j, n, m, st, dr = 1e9, pivot, rs, a[20][N], p[20];
bool viz[20];

bool canAdd(int x, int lvl) {
  if(!lvl) return 1;
  for(int i = 0; i < m; ++i)
    if(abs(a[x][i] - a[p[lvl - 1]][i]) < pivot) return 0;
  if(lvl == n - 1) {
    for(int i = 0; i < m - 1; ++i)
      if(abs(a[x][i] - a[p[0]][i + 1]) < pivot) return 0;
  }
  return 1;
}

bool finalCheck() {
  if(n == 1) {
    for(int i = 0; i < m - 1; ++i) if(abs(a[0][i] - a[0][i + 1]) < pivot) return 0;
    return 1;
  }
  return 1;
}

bool back(int lvl) {
  if(lvl == n) return finalCheck();

  for(int i = 0; i < n; ++i)
    if(!viz[i] && canAdd(i, lvl)) {
      p[lvl] = i;
      viz[i] = 1;
      if(back(lvl + 1)) return 1;
      viz[i] = 0;
      p[lvl] = 0;
    }

  return 0;
}

int main() {
  scanf("%d %d", &n, &m);
  for(i = 0; i < n; ++i)
    for(j = 0; j < m; ++j)
      scanf("%d", a[i] + j);

  while(st <= dr) {
    pivot = (st + dr) / 2;
    memset(viz, 0, sizeof(viz));
    if(back(0)) rs = pivot, st = pivot + 1;
    else dr = pivot - 1;
  }

  printf("%d\n", rs);

  return 0;
}


#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int i, j, n, m, st, dr = 1e9, pivot, rs, a[20][N], p[20];
bool viz[20];
map<pair<int, int>, int> M1, M2;

bool canAdd(int x, int lvl) {
  if(!lvl) return 1;
  auto curr = make_pair(x, p[lvl - 1]);
  if(M1[curr] < pivot) return 0;
  for(int i = 0; i < m; ++i)
    if(abs(a[x][i] - a[p[lvl - 1]][i]) < pivot) return 0;
  if(lvl == n - 1) {
    curr = make_pair(x, p[0]);
    if(M2[curr] < pivot) return 0;
    for(int i = 0; i < m - 1; ++i)
      if(abs(a[x][i] - a[p[0]][i + 1]) < pivot) return M2[curr] = 0;
  }
  return 1;
}

bool finalCheck() {
  if(n == 1) {
    for(int i = 0; i < m - 1; ++i) if(abs(a[0][i] - a[0][i + 1]) < pivot) return 0;
    return 1;
  }
  return 1;
}

int getVal1(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m; ++i) ans = min(abs(a[x][i] - a[y][i]), ans);
  return ans;
}

int getVal2(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m - 1; ++i) ans = min(abs(a[x][i] - a[y][i + 1]), ans);
  return ans;
}

bool back(int lvl) {
  if(lvl == n) return finalCheck();

  for(int i = 0; i < n; ++i)
    if(!viz[i] && canAdd(i, lvl)) {
      p[lvl] = i;
      viz[i] = 1;
      if(back(lvl + 1)) return 1;
      viz[i] = 0;
      p[lvl] = 0;
    }

  return 0;
}

int main() {
  scanf("%d %d", &n, &m);
  for(i = 0; i < n; ++i)
    for(j = 0; j < m; ++j)
      scanf("%d", a[i] + j);

  for(i = 0; i < n; ++i)
    for(j = 0; j < n; ++j)
      if(i != j) M1[make_pair(i, j)] = getVal1(i, j), M2[make_pair(i, j)] = getVal2(i, j);

  while(st <= dr) {
    pivot = (st + dr) / 2;
    memset(viz, 0, sizeof(viz));
    if(back(0)) rs = pivot, st = pivot + 1;
    else dr = pivot - 1;
  }

  printf("%d\n", rs);

  return 0;
}


#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int i, j, n, m, st, dr, pivot, rs, a[20][N], p[20], M1[20][20], M2[20][20], order[20];
bool viz[20];

bool canAdd(int x, int lvl) {
  if(!lvl) return 1;
  if(M1[x][p[lvl - 1]] < pivot) return 0;
  if(lvl == n - 1 && M2[x][p[0]] < pivot) return 0;
  return 1;
}

bool finalCheck() {
  if(n == 1) {
    for(int i = 0; i < m - 1; ++i) if(abs(a[0][i] - a[0][i + 1]) < pivot) return 0;
    return 1;
  }
  return 1;
}

int getVal1(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m; ++i) ans = min(abs(a[x][i] - a[y][i]), ans);
  return ans;
}

int getVal2(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m - 1; ++i) ans = min(abs(a[x][i] - a[y][i + 1]), ans);
  return ans;
}

bool back(int lvl) {
  if(lvl == n) return finalCheck();

  for(int i = 0; i < n; ++i)
    if(!viz[order[i]] && canAdd(order[i], lvl)) {
      p[lvl] = order[i];
      viz[order[i]] = 1;
      if(back(lvl + 1)) return 1;
      viz[order[i]] = 0;
      p[lvl] = 0;
    }

  return 0;
}

int main() {
  srand(time(0));
  scanf("%d %d", &n, &m);
  for(i = 0; i < n; ++i)
    for(j = 0; j < m; ++j)
      scanf("%d", a[i] + j), dr = max(dr, a[i][j]);

  for(i = 0; i < n; ++i) order[i] = i;
  random_shuffle(order, order + n);

  for(i = 0; i < n; ++i)
    for(j = 0; j < n; ++j)
      if(i != j) M1[i][j] = getVal1(i, j), M2[i][j] = getVal2(i, j);

  while(st <= dr) {
    pivot = (st + dr) / 2;
    memset(viz, 0, sizeof(viz));
    if(back(0)) rs = pivot, st = pivot + 1;
    else dr = pivot - 1;
  }

  printf("%d\n", rs);

  return 0;
}


#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int i, j, n, m, st, dr = 1e9, pivot, rs, a[20][N], p[20], M1[20][20], M2[20][20];
bool viz[20];

bool canAdd(int x, int lvl) {
  if(!lvl) return 1;
  if(M1[x][p[lvl - 1]] < pivot) return 0;
  if(lvl == n - 1 && M2[x][p[0]] < pivot) return 0;
  return 1;
}

bool finalCheck() {
  if(n == 1) {
    for(int i = 0; i < m - 1; ++i) if(abs(a[0][i] - a[0][i + 1]) < pivot) return 0;
    return 1;
  }
  return 1;
}

int getVal1(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m; ++i) ans = min(abs(a[x][i] - a[y][i]), ans);
  return ans;
}

int getVal2(int x, int y) {
  int ans = 1e9;
  for(int i = 0; i < m - 1; ++i) ans = min(abs(a[x][i] - a[y][i + 1]), ans);
  return ans;
}

bool back(int lvl) {
  if(lvl == n) return finalCheck();

  for(int i = 0; i < n; ++i)
    if(!viz[i] && canAdd(i, lvl)) {
      p[lvl] = i;
      viz[i] = 1;
      if(back(lvl + 1)) return 1;
      viz[i] = 0;
      p[lvl] = 0;
    }

  return 0;
}

int main() {
  scanf("%d %d", &n, &m);
  for(i = 0; i < n; ++i)
    for(j = 0; j < m; ++j)
      scanf("%d", a[i] + j);

  for(i = 0; i < n; ++i)
    for(j = 0; j < n; ++j)
      if(i != j) M1[i][j] = getVal1(i, j), M2[i][j] = getVal2(i, j);

  while(st <= dr) {
    pivot = (st + dr) / 2;
    memset(viz, 0, sizeof(viz));
    if(back(0)) rs = pivot, st = pivot + 1;
    else dr = pivot - 1;
  }

  printf("%d\n", rs);

  return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

bool dp[ 1 << MAXN ][ MAXN + 1 ], valid[ MAXN + 1 ][ MAXN + 1 ];

bool check( int K ) {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            dp[ i ][ j ] = false;
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            valid[ i ][ j ] = true;
            bool status = true;
            for( int k = 0; k < M; k++ ) {
                if( abs( grid[ i ][ k ]  - grid[ j ][ k ] ) < K ) {
                    status = false;
                }
            }
            valid[ i ][ j ] = status;
        }
    }
    for( int irow = 0; irow < N; irow++ ) {
        dp[ 1 << irow ][ irow ] = true;
        for( int bit = 0; bit < ( 1 << N ); bit++ ) {
            if( !( bit & ( 1 << irow ) ) ) continue;
            for( int i = 0; i < N; i++ ) {
                if( !( bit & ( 1 << i ) ) || i == irow ) continue;
                for( int j = 0; j < N; j++ ) {
                    if( i == j ) continue;
                    if( !( bit & ( 1 << j ) ) ) continue;
                    if( valid[ j ][ i ] && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                        dp[ bit ][ i ] = true;
                    }
                }
            }
        }
        for( int i = 0; i < N; i++ ) {
            if( i == irow ) continue;
            bool status = true;
            for( int k = 0; k < M - 1; k++ ) {
                if( abs( grid[ i ][ k ] - grid[ irow ][ k + 1 ] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}
int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

int dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int irow = 0; irow < N; irow++ ) {
        for( int i = 0; i < 1 << N; i++ ) {
            for( int j = 0; j < N; j++ ) {
                dp[ i ][ j ] = false;
            }
        }
        dp[ 1 << irow ][ irow ] = true;
        for( int bit = 0; bit < ( 1 << N ); bit++ ) {
            if( !( bit & ( 1 << irow )  ) ) continue;
            for( int i = 0; i < N; i++ ) {
                if( !( bit & ( 1 << i ) ) ) continue;
                if( i == irow ) continue;
                for( int j = 0; j < N; j++ ) {
                    if( i == j ) continue;
                    if( !( bit & ( 1 << j ) ) ) continue;
                    bool status = true;
                    for( int k = 0; k < M; k++ ) {
                        if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                    }
                    if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                        dp[ bit ][ i ] = true;
                    }
                }
            }
        }
        for( int i = 0; i < N; i++ ) {
            if( i == irow ) continue;
            bool status = true;
            for( int j = 0; j < M - 1; j++ ) {
                if( abs( grid[ i ][ j ] - grid[ irow ][ j + 1] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}

int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

bool dp[ 1 << MAXN ][ MAXN + 1 ], valid[ MAXN + 1 ][ MAXN + 1 ];

bool check( int K ) {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            dp[ i ][ j ] = false;
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            valid[ i ][ j ] = true;
            bool status = true;
            for( int k = 0; k < M; k++ ) {
                if( abs( grid[ i ][ k ]  - grid[ j ][ k ] ) < K ) {
                    status = false;
                }
            }
            valid[ i ][ j ] = status;
        }
    }
    for( int i = 0; i < N; i++ ) dp[ 1 << i ][ i ] = true;
    for( int bit = 0; bit < ( 1 << N ); bit++ ) {
        for( int i = 0; i < N; i++ ) {
            if( !( bit & ( 1 << i ) ) ) continue;
            for( int j = 0; j < N; j++ ) {
                if( i == j ) continue;
                if( !( bit & ( 1 << j ) ) ) continue;
                if( valid[ j ][ i ] && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                    dp[ bit ][ i ] = true;
                }
            }
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            if( i == j ) continue;
            bool status = true;
            for( int k = 0; k < M - 1; k++ ) {
                if( abs( grid[ i ][ k ] - grid[ j ][ k + 1 ] ) < K ) status = false;
            }
            if( status && dp[ ( ( 1 << N ) - 1 ) ^ ( 1 << j ) ][ i ] ) return true;
        }
    }
    return false;
}
int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

int dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int irow = 0; irow < N; irow++ ) {
        for( int i = 0; i < 1 << N; i++ ) {
            for( int j = 0; j < N; j++ ) {
                dp[ i ][ j ] = false;
            }
        }
        dp[ 1 << irow ][ irow ] = true;
        for( int bit = 0; bit < ( 1 << N ); bit++ ) {
            if( !( bit & ( 1 << irow )  ) ) continue;
            for( int i = 0; i < N; i++ ) {
                dp[ bit ][ i ] = false;
                if( !( bit & ( 1 << i ) ) ) continue;
                if( i == irow ) continue;
                for( int j = 0; j < N; j++ ) {
                    if( i == j ) continue;
                    if( !( bit & ( 1 << j ) ) ) continue;
                    bool status = true;
                    for( int k = 0; k < M; k++ ) {
                        if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                    }
                    if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                        dp[ bit ][ i ] = true;
                        break;
                    }
                }
            }
        }
        for( int i = 0; i < N; i++ ) {
            if( i == irow ) continue;
            bool status = true;
            for( int j = 0; j < M - 1; j++ ) {
                if( abs( grid[ i ][ j ] - grid[ irow ][ j + 1 ] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}

int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ), val );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

bool dp[ 1 << MAXN ][ MAXN + 1 ], valid[ MAXN + 1 ][ MAXN + 1 ];

bool check( int K ) {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            dp[ i ][ j ] = false;
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            valid[ i ][ j ] = true;
            bool status = true;
            for( int k = 0; k < M; k++ ) {
                if( abs( grid[ i ][ k ]  - grid[ j ][ k ] ) < K ) {
                    status = false;
                }
            }
            valid[ i ][ j ] = status;
        }
    }
    for( int i = 0; i < N; i++ ) dp[ 1 << i ][ i ] = true;
    for( int bit = 0; bit < ( 1 << N ); bit++ ) {
        for( int i = 0; i < N; i++ ) {
            if( !( bit & ( 1 << i ) ) ) continue;
            for( int j = 0; j < N; j++ ) {
                if( i == j ) continue;
                if( !( bit & ( 1 << j ) ) ) continue;
                if( valid[ j ][ i ] && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                    dp[ bit ][ i ] = true;
                }
            }
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            if( i == j ) continue;
            bool status = true;
            for( int k = 0; k < M - 1; k++ ) {
                if( abs( grid[ i ][ k ] - grid[ j ][ k + 1 ] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}
int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 16
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

int dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int irow = 0; irow < N; irow++ ) {
        for( int i = 0; i < 1 << N; i++ ) {
            for( int j = 0; j < N; j++ ) {
                dp[ i ][ j ] = false;
            }
        }
        dp[ 1 << irow ][ irow ] = true;
        for( int bit = 0; bit < ( 1 << N ); bit++ ) {
            if( !( bit & ( 1 << irow )  ) ) continue;
            for( int i = 0; i < N; i++ ) {
                if( !( bit & ( 1 << i ) ) ) continue;
                for( int j = 0; j < N; j++ ) {
                    if( i == j ) continue;
                    if( !( bit & ( 1 << j ) ) ) continue;
                    bool status = true;
                    for( int k = 0; k < M; k++ ) {
                        if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                    }
                    if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                        dp[ bit ][ i ] = true;
                    }
                }
            }
        }
        for( int i = 0; i < N; i++ ) {
            if( i == irow ) continue;
            bool status = true;
            for( int j = 0; j < M - 1; j++ ) {
                if( abs( grid[ i ][ j ] - grid[ irow ][ j + 1] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}

int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

int dp[ 1 << MAXN ][ MAXN + 1 ][ MAXN + 1 ];
int myval[ MAXN + 1 ][ MAXN + 1 ];

int compute() {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            for( int k = 0; k < N; k++ ) {
                dp[ i ][ j ][ k ] = 0;
            }
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            myval[ i ][ j ] = 1000000100;
            for( int k = 0; k < M; k++ ) {
                myval[ i ][ j ] = min( myval[ i ][ j ], abs( grid[ i ][ k ]  - grid[ j ][ k ] ) );
            }
        }
    }
    for( int i = 0; i < N; i++ ) dp[ 1 << i ][ i ][ i ] = 1000000100;
    for( int bit = 0; bit < ( 1 << N ); bit++ ) {
        for( int i = 0; i < N; i++ ) {
            if( !( bit & ( 1 << i ) ) ) continue;
            for( int j = 0; j < N; j++ ) {
                if( i == j ) continue;
                if( !( bit & ( 1 << j ) ) ) continue;
                for( int k = 0; k < N; k++ ) {
                    if(  k == i ) continue;
                    if( !( bit & ( 1 << k ) ) ) continue;
                    dp[ bit ][ i ][ j ] = max( dp[ bit ][ i ][ j ], min( dp[ bit ^ ( 1 << i ) ][ k ][ j ], myval[ i ][ k ] ) );
                }
            }
        }
    }
    int ans = 0;
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            if( i == j ) continue;
            bool status = true;
            int val = 1000000100;
            for( int k = 0; k < M - 1; k++ ) {
                val = min( val, abs( grid[ i ][ k ] - grid[ j ][ k + 1 ] ) );
            }
            ans = max( ans, min( dp[ ( 1 << N ) - 1 ][ i ][ j ], val ) );
        }
    }
    return ans;
}

int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int ans = compute();
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

bool dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            dp[ i ][ j ] = false;
        }
    }
    for( int i = 0; i < N; i++ ) dp[ 1 << i ][ i ] = true;
    for( int bit = 0; bit < ( 1 << N ); bit++ ) {
        for( int i = 0; i < N; i++ ) {
            if( !( bit & ( 1 << i ) ) ) continue;
            for( int j = 0; j < N; j++ ) {
                if( i == j ) continue;
                if( !( bit & ( 1 << j ) ) ) continue;
                bool status = true;
                for( int k = 0; k < M; k++ ) {
                    if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                }
                if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                    dp[ bit ][ i ] = true;
                }
            }
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            if( i == j ) continue;
            bool status = true;
            for( int k = 0; k < M - 1; k++ ) {
                if( abs( grid[ i ][ j ] - grid[ j ][ j + 1] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}
int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

int dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int irow = 0; irow < N; irow++ ) {
        for( int i = 0; i < 1 << N; i++ ) {
            for( int j = 0; j < N; j++ ) {
                dp[ i ][ j ] = false;
            }
        }
        dp[ 1 << irow ][ irow ] = true;
        for( int bit = 0; bit < ( 1 << N ); bit++ ) {
            if( !( bit & ( 1 << irow )  ) ) continue;
            for( int i = 0; i < N; i++ ) {
                if( !( bit & ( 1 << i ) ) ) continue;
                if( i == irow ) continue;
                for( int j = 0; j < N; j++ ) {
                    if( i == j ) continue;
                    if( !( bit & ( 1 << j ) ) ) continue;
                    bool status = true;
                    for( int k = 0; k < M; k++ ) {
                        if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                    }
                    if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                        dp[ bit ][ i ] = true;
                    }
                }
            }
        }
        for( int i = 0; i < N; i++ ) {
            if( i == irow ) continue;
            bool status = true;
            for( int j = 0; j < M - 1; j++ ) {
                if( abs( grid[ i ][ j ] - grid[ irow ][ j + 1] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}

int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


#include <cstdio>
#include <algorithm>

#define MAXN 17
#define MAXM 10100

using namespace std;

int N, M, grid[ MAXN + 1 ][ MAXM + 1 ];

bool dp[ 1 << MAXN ][ MAXN + 1 ];

bool check( int K ) {
    for( int i = 0; i < 1 << N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            dp[ i ][ j ] = false;
        }
    }
    for( int i = 0; i < N; i++ ) dp[ 1 << i ][ i ] = true;
    for( int bit = 0; bit < ( 1 << N ); bit++ ) {
        for( int i = 0; i < N; i++ ) {
            if( !( bit & ( 1 << i ) ) ) continue;
            for( int j = 0; j < N; j++ ) {
                if( i == j ) continue;
                if( !( bit & ( 1 << j ) ) ) continue;
                bool status = true;
                for( int k = 0; k < M; k++ ) {
                    if( abs( grid[ i ][ k ] - grid[ j ][ k ] ) < K ) status = false;
                }
                if( status && dp[ bit ^ ( 1 << i ) ][ j ] ) {
                    dp[ bit ][ i ] = true;
                }
            }
        }
    }
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < N; j++ ) {
            if( i == j ) continue;
            bool status = true;
            for( int k = 0; k < M - 1; k++ ) {
                if( abs( grid[ i ][ k ] - grid[ j ][ k + 1 ] ) < K ) status = false;
            }
            if( status && dp[ ( 1 << N ) - 1 ][ i ] ) return true;
        }
    }
    return false;
}
int main( void ) {
    scanf("%d%d", &N, &M );
    for( int i = 0; i < N; i++ ) {
        for( int j = 0; j < M; j++ ) {
            scanf("%d", &grid[ i ][ j ] );
        }
    }
    if( N == 1 ) {
        int val = 1000000100;
        for( int i = 1; i < M; i++ ) {
            val = min( val, abs( grid[ 0 ][ i ] - grid[ 0 ][ i - 1 ] ) );
        }
        printf("%d\n", val );
        return 0;
    }
    int lo = 0, hi = 1000000100, ans = 0;
    while( lo <= hi ) {
        int mid = ( lo + hi ) / 2;
        int status = check( mid );
        if( status ) {
            ans = mid;
            lo = mid + 1;
        } else {
            hi = mid - 1;
        }
    }
    printf("%d\n", ans );
    return 0;
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int mask , int ind , int val )
{
    if( (1<<n) - 1 == mask )
    {
        return min( val , adj1[pos][ind] ) ;
    }
    if( dp[pos][mask] != -1 )
        return dp[pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) )
        continue ;
        cnt = max( cnt , brute( i , mask|(1<<i) , ind , adj[pos][i] ) ) ;
    }
    cnt = min( cnt , val ) ;
    dp[pos][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    if( n == 1 )
        return cout << adj1[0][0] , 0 ;
    memset( dp , -1 , sizeof(dp ) ) ;
    int ans = 0 ;
    for( int i = 0 ; i < n ; i++ )
        ans = max( ans , brute( i , 1<<i , i , INT_MAX ) ) ;
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][20][1<<16] , n , m ;
int brute( int pos , int mask , int ind )
{
    if( (1<<n) - 1 == mask )
    return adj1[ind][pos] ;
    if( dp[ind][pos][mask] != -1 )
        return dp[ind][pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) == 0 )
        cnt = max( cnt , min( adj[pos][i] , brute( i , mask|(1<<i) , ind ) ) ) ;
    }
    dp[ind][pos][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    if( n == 1 )
        return cout << adj1[0][0] , 0 ;
    memset( dp , -1 , sizeof(dp ) ) ;
    int ans = 0 ;
    for( int i = 0 ; i < n ; i++ )
      ans = max( ans , brute( i , 1<<i , i ) ) ;
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int id , int mask , int k , int ind )
{
    if( pos == n - 1 )
    {
        for( int i = 0 ; i < n ; i++ )
        {
            if( ( mask & ( 1 << i ) ) == 0 )
            {
                int x = INT_MAX ;
                for( int j = 1 ; j < m ; j++ )
                    x = min( x , abs( a[ind][j] - a[i][j-1] ) ) ;
                x = min( x , adj[id][i] ) ;
                if( x < k )
                    return 0 ;
                return 1 ;
            }
        }
    }
    if( dp[id][mask] != -1 )
        return dp[id][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) == 0 && adj[id][i] >= k )
            cnt = max( cnt , brute( pos + 1 , i , mask|(1<<i) , k , ind ) ) ;
    }
    dp[id][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    if( n == 1 )
        return cout << adj1[0][0] , 0 ;
    int lo = 0 , hi = 1e10 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        int p = 0 ;
        for( int i = 0 ; i < n ; i++ )
            p = max( p , brute( 1 , i , (1<<i) , mid , i ) ) ;
        if( p )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int id , int mask , int k , int ind )
{
    if( pos == n - 1 )
    {
        for( int i = 0 ; i < n ; i++ )
        {
            if( ( mask & ( 1 << i ) ) == 0 )
            {
                int x = INT_MAX ;
                for( int j = 1 ; j < m ; j++ )
                    x = min( x , abs( a[ind][j] - a[i][j-1] ) ) ;
                x = min( x , adj[id][i] ) ;
                if( x < k )
                    return 0 ;
                return 1 ;
            }
        }
    }
    if( dp[id][mask] != -1 )
        return dp[pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) == 0 && adj[id][i] >= k )
            cnt = max( cnt , brute( pos + 1 , i , mask|(1<<i) , k , ind ) ) ;
    }
    dp[id][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    if( n == 1 )
        return cout << adj1[0][0] , 0 ;
    int lo = 0 , hi = 1e10 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        int p = 0 ;
        for( int i = 0 ; i < n ; i++ )
            p = max( p , brute( 1 , i , (1<<i) , mid , i ) ) ;
        if( p )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int mask , int k )
{
    if( pos == n )
    return 1 ;
    if( dp[pos][mask] != -1 )
        return dp[pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( i == pos )
            continue ;
        if( pos == n - 1 && adj1[pos][i] < k )
        continue ;
        if( ( mask & ( 1 << i ) ) == 0 && adj[pos][i] >= k )
        cnt = max( cnt , brute( pos + 1 , mask|(1<<i) , k ) ) ;
    }
    dp[pos][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( x , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    int lo = 0 , hi = 1e10 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        if( brute( 0 , 0 , mid ) )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[16][16][1<<16] , n , m ;
int brute( int pos , int id , int mask , int k , int ind )
{
    if( pos == n - 1 )
    {
        for( int i = 0 ; i < n ; i++ )
        {
            if( ( mask & ( 1 << i ) ) == 0 )
            {
                int x = INT_MAX ;
                for( int j = 1 ; j < m ; j++ )
                    x = min( x , abs( a[ind][j] - a[i][j-1] ) ) ;
                x = min( x , adj[id][i] ) ;
                if( x < k )
                    return 0 ;
                return 1 ;
            }
        }
    }
    if( dp[pos][id][mask] != -1 )
        return dp[pos][id][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) == 0 && adj[id][i] >= k )
            cnt = max( cnt , brute( pos + 1 , i , mask|(1<<i) , k , ind ) ) ;
    }
    dp[pos][id][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    if( n == 1 )
        return cout << adj1[0][0] , 0 ;
    int lo = 0 , hi = 1e9 + 5 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        int p = 0 ;
        for( int i = 0 ; i < n ; i++ )
            p = max( p , brute( 1 , i , (1<<i) , mid , i ) ) ;
        if( p )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int mask , int k , int ind )
{
    if( pos == n - 1 )
    {
        for( int i = 0 ; i < n ; i++ )
        {
            if( ( mask & ( 1 << i ) ) == 0 )
            {
                int x = INT_MAX ;
                for( int j = 1 ; j < m ; j++ )
                    x = min( x , abs( a[ind][j] - a[i][j-1] ) ) ;
                if( x < k )
                    return 0 ;
                return 1 ;
            }
        }
    }
    if( dp[pos][mask] != -1 )
        return dp[pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( i == pos )
            continue ;
        if( ( mask & ( 1 << i ) ) == 0 && adj[pos][i] >= k )
        {
            if( pos == 0 )
                cnt = max( cnt , brute( pos + 1 , mask|(1<<i) , k , i ) ) ;
            else
                cnt = max( cnt , brute( pos + 1 , mask|(1<<i) , k , ind ) ) ;
        }
    }
    dp[pos][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    int lo = 0 , hi = 1e10 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        if( brute( 0 , 0 , mid , 0 ) )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}


// end of patience
#include<bits/stdc++.h>
using namespace std ;
#define int long long int
#define F first
#define S second
#define pb push_back
int a[20][10005] , adj[20][20] , adj1[20][20] ;
int dp[20][1<<16] , n , m ;
int brute( int pos , int id , int mask , int k , int ind )
{
    if( pos == n - 1 )
    {
        for( int i = 0 ; i < n ; i++ )
        {
            if( ( mask & ( 1 << i ) ) == 0 )
            {
                int x = INT_MAX ;
                for( int j = 1 ; j < m ; j++ )
                    x = min( x , abs( a[ind][j] - a[i][j-1] ) ) ;
                x = min( x , adj[id][i] ) ;
                if( x < k )
                    return 0 ;
                return 1 ;
            }
        }
    }
    if( dp[id][mask] != -1 )
        return dp[pos][mask] ;
    int cnt = 0 ;
    for( int i = 0 ; i < n ; i++ )
    {
        if( ( mask & ( 1 << i ) ) == 0 && adj[id][i] >= k )
            cnt = max( cnt , brute( pos + 1 , i , mask|(1<<i) , k , ind ) ) ;
    }
    dp[id][mask] = cnt ;
    return cnt ;
}
signed main()
{
    ios_base::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    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++ )
        {
            int x = INT_MAX , xx = INT_MAX ;
            for( int k = 0 ; k < m ; k++ )
            {
                x = min( x , abs( a[i][k] - a[j][k] ) ) ;
                if( k < m - 1 )
                    xx = min( xx , abs( a[j][k] - a[i][k+1] ) ) ;
            }
            adj[i][j] = x ;
            adj1[i][j] = xx ;
        }
    }
    int lo = 0 , hi = 1e10 ;
    int ans = 0 ;
    while( lo <= hi )
    {
        int mid = ( lo + hi ) / 2 ;
        memset( dp , -1 , sizeof( dp ) ) ;
        int p = 0 ;
        for( int i = 0 ; i < n ; i++ )
            p = max( p , brute( 1 , i , (1<<i) , mid , i ) ) ;
        if( p )
            lo = mid + 1 , ans = mid ;
        else
            hi = mid - 1 ;
    }
    cout << ans ;
    cerr << "Time elapsed : " << 1.0 * clock() / CLOCKS_PER_SEC << " sec \n";
}