#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 1e4, oo = 1e9;

graph g(N);

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N][N];

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l].clear();

    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i].push_back(j);
            }

    for (int mask = 0; mask < (1 << n); ++mask)
        for (int i = 0; i < n; ++i)
            dp[mask][i] = -1;

    for (int i = 0; i < n; ++i) dp[1 << i][i] = i;

    for (int mask = 3; mask < (1 << n); ++mask) {
        for (int i = 0; i < n; ++i) {
            if (!bit(mask, i)) continue;
            for (int v : g[i])
                if (bit(mask, v) && dp[remove_bit(mask, i)][v] != -1) {
                    dp[mask][i] = dp[remove_bit(mask, i)][v];
                    break;
                }
        }
    }

    for (int last = 0; last < n; ++last) {
        int first = dp[(1 << n) - 1][last];
        if (first != -1 && min_dif2[first][last] >= k)
            return true;

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = oo;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 1e4, oo = 1e9;

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N];
int g[N];

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l] = 0;

    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i] |= (1 << j);
                g[j] |= (1 << i);
            }

    for (int i = 0; i < n; ++i) {
        dp[1 << i] = 1 << i;
        for (int mask = (1 << i) + 1; mask < (1 << n); ++mask) {
            dp[mask] = 0;
            if (!bit(mask, i)) continue;
            for (int j = 0; j < n; ++j) {
                if (!bit(mask, j)) continue;
                dp[mask] |= (1 << j) * ((dp[remove_bit(mask, j)] & g[j]) > 0);
            }
        }

        int reach = dp[(1 << n) - 1];
        for (int l = 0; l < n; ++l) {
            if (!bit(reach, l)) continue;
            if (min_dif2[i][l] >= k) return true;
        }

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = oo;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 1e4, oo = 1e9;

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N];
int g[N];

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l] = 0;

    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i] |= (1 << j);
                g[j] |= (1 << i);
            }

    for (int i = 0; i < n; ++i) {
        memset(dp, 0, sizeof(dp));
        dp[1<<i] = 1 << i;
        for (int mask = (1 << i) + 1; mask < (1 << n); ++mask) {
            if (!bit(mask, i)) continue;
            for (int j = 0; j < n; ++j) {
                if (!bit(mask, j)) continue;
                dp[mask] |= (1 << j) * ((dp[remove_bit(mask, j)] & g[j]) > 0);
            }
        }

        int reach = dp[(1 << n) - 1];
        for (int l = 0; l < n; ++l) {
            if (!bit(reach, l)) continue;
            if (min_dif2[i][l] >= k) return true;
        }

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = oo;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 1e4, oo = 1e9;

graph g(N);

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N][N];

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l].clear();

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i].push_back(j);
            }

    for (int mask = 0; mask < (1 << n); ++mask)
        for (int i = 0; i < n; ++i)
            dp[mask][i] = -1;

    for (int i = 0; i < n; ++i) dp[1 << i][i] = i;

    for (int mask = 3; mask < (1 << n); ++mask) {
        for (int i = 0; i < n; ++i) {
            if (!bit(mask, i)) continue;
            for (int v : g[i])
                if (bit(mask, v) && dp[remove_bit(mask, i)][v] != -1) {
                    dp[mask][i] = dp[remove_bit(mask, i)][v];
                    break;
                }
        }
    }

    for (int last = 0; last < n; ++last) {
        int first = dp[(1 << n) - 1][last];
        if (first != -1 && min_dif2[first][last] >= k)
            return true;

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = oo;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 10000;

graph g(N);

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N][N];

bool last_edge(int i, int j, int k) {
    for (int l = 0; l < m - 1; ++l) {
        if (abs(a[j][l] - a[i][l + 1]) < k) return false;
    }
    return true;
}

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l].clear();

    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i].push_back(j);
                g[j].push_back(i);
            }

    for (int i = 0; i < n; ++i)
        if (!g[i].size()) return false;

    for (int mask = 0; mask < (1 << n); ++mask)
        for (int i = 0; i < n; ++i)
            dp[mask][i] = -1;

    for (int i = 0; i < n; ++i) dp[1 << i][i] = i;

    for (int mask = 3; mask < (1 << n); ++mask) {
        for (int i = 0; i < n; ++i) {
            if (!bit(mask, i)) continue;
            for (int v : g[i])
                if (bit(mask, v) && dp[remove_bit(mask, i)][v] != -1) {
                    dp[mask][i] = dp[remove_bit(mask, i)][v];
                    break;
                }
        }
    }

    for (int last = 0; last < n; ++last) {
        int first = dp[(1 << n) - 1][last];
        if (first != -1 && min_dif2[first][last] >= k)
            return true;

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = 1000000000;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = 1000000000;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = 1000000000;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include <bits/stdc++.h>

#define bit(mask, i) (mask & (1 << i))
#define remove_bit(mask, i) (mask & ~(1<<i))
using namespace std;

typedef vector<int> vi;
typedef long long int ll;

typedef vector<vi> graph;

const int N = 16, M = 1e4, oo = 1e9;

int n, m;

int a[N][M];
int min_dif1[N][N];
int min_dif2[N][N];
int dp[1 << N];
int g[N];

bool is_acceptable(int k) {

    for (int l = 0; l < n; ++l) g[l] = 0;

    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            if (min_dif1[i][j] >= k) {
                g[i] |= (1 << j);
                g[j] |= (1 << i);
            }

    for (int i = 0; i < n; ++i) {
        memset(dp, 0, sizeof(dp));
        dp[0] = g[i];
        for (int mask = 0; mask < (1 << n); ++mask) {
            if (!bit(mask, i)) continue;
            for (int j = 0; j < n; ++j) {
                if (!bit(mask, j)) continue;
                dp[mask] |= (1 << j) * ((dp[remove_bit(mask, j)] & g[j]) > 0);
            }
        }

        int reach = dp[(1 << n) - 1];
        for (int l = 0; l < n; ++l) {
            if (!bit(reach, l)) continue;
            if (min_dif2[i][l] >= k) return true;
        }

    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.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 = i + 1; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m; ++k)
                v = min(v, abs(a[i][k] - a[j][k]));
            min_dif1[i][j] = v;
            min_dif1[j][i] = v;
        }

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int v = oo;
            for (int k = 0; k < m - 1; ++k)
                v = min(v, abs(a[j][k] - a[i][k + 1]));
            min_dif2[i][j] = v;
        }

    int l = 0, r = oo;
    while (l < r - 1) {
        int mid = (l + r) / 2;
        if (is_acceptable(mid))
            l = mid;
        else
            r = mid;
    }
    cout << l << endl;
    return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll       long long

#define  sci(x)   scanf("%d", &x)
#define  scl(x)   scanf("%lld", &x)
#define  scd(x)   scanf("%lf", &x)

#define  pfi(x)   printf("%d", x)
#define  pfl(x)   printf("%lld", x)
#define  pfd(x)   printf("%lf", x)
#define  pfc(x)   printf("Case %d: ", x++)
#define  ps       printf(" ")
#define  pn       printf("\n")

#define  pb       push_back
#define  ppb      pop_back
#define  pf       push_front
#define  ppf      pop_front
#define  In       insert
#define  All(a)   a.begin(), a.end()

int data[16][10005];
int normal[16][16], firstLast[16][16], n, first;

int solve(int mask, int from)
{
	if(__builtin_popcount(mask) == n)
	{
		//cout << first << ' ' << from << ' ' << firstLast[first][from] << endl;
		return firstLast[first][from];
	}
	int ret = 0, p;
	for(int i = 0; i < n; i++)
		if(!(mask & (1 << i)))
		{
			p = solve(mask | (1 << i), i);
			//cout << from << ' ' << i << ' '<< normal[from][i] << ' '<< p<< endl;
			ret = max(ret, min(normal[from][i], p));
		}
	//cout << mask << ' ' << ret << endl;
	return ret;
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int m;
    sci(n), sci(m);

    int i, j, k, maxim;

    for(i = 0; i < n; i++)
    	for(j = 0; j < m; j++)
    		sci(data[i][j]);

    /*if(n == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < m - 1; i++)
    		ans = min(ans, abs(data[0][i] - data[0][i + 1]));
    	printf("%d\n", ans);
    	return 0;
    }
    if(m == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < n - 1; i++)
    		ans = min(ans, abs(data[i][0] - data[i + 1][0]));
    	printf("%d\n", ans);
    	return 0;
    }*/

    for(i = 0; i < n; i++)
    {
    	for(j = 0; j < n; j++)
    	{
    		/*if(i == j)
    			continue;*/
    		maxim = INT_MAX;

    		for(k = 0; k < m; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k]));
    		normal[i][j] = maxim;

    		maxim = INT_MAX;
    		for(k = 0; k < m - 1; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k + 1]));
    		firstLast[j][i] = maxim;
    		//cout << i << ' ' << j << ' ' << normal[i][j] << ' ' << firstLast[j][i] << endl;
    	}
    }
    int ans = 0;
    for(i = 0; i < n; i++)
    {
    	first = i;
    	ans = max(ans, solve(1 << i, i));
    }

    cout << ans;

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll       long long

#define  sci(x)   scanf("%d", &x)
#define  scl(x)   scanf("%lld", &x)
#define  scd(x)   scanf("%lf", &x)

#define  pfi(x)   printf("%d", x)
#define  pfl(x)   printf("%lld", x)
#define  pfd(x)   printf("%lf", x)
#define  pfc(x)   printf("Case %d: ", x++)
#define  ps       printf(" ")
#define  pn       printf("\n")

#define  pb       push_back
#define  ppb      pop_back
#define  pf       push_front
#define  ppf      pop_front
#define  In       insert
#define  All(a)   a.begin(), a.end()

int data[16][10005];
int normal[16][16], firstLast[16][16], n, first;

int solve(int mask, int from)
{
	if(__builtin_popcount(mask) == n)
	{
		//cout << first << ' ' << from << ' ' << firstLast[first][from] << endl;
		return firstLast[first][from];
	}
	int ret = 0, p;
	for(int i = 0; i < n; i++)
		if(!(mask & (1 << i)))
		{
			p = solve(mask | (1 << i), i);
			//cout << from << ' ' << i << ' '<< normal[from][i] << ' '<< p<< endl;
			ret = max(ret, min(normal[from][i], p));
		}
	//cout << mask << ' ' << ret << endl;
	return ret;
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int m;
    sci(n), sci(m);

    int i, j, k, maxim;

    for(i = 0; i < n; i++)
    	for(j = 0; j < m; j++)
    		sci(data[i][j]);

    if(n == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < m - 1; i++)
    		ans = min(ans, abs(data[0][i] - data[0][i + 1]));
    	printf("%d\n", ans);
    	return 0;
    }
    if(m == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < n - 1; i++)
    		ans = min(ans, abs(data[i][0] - data[i + 1][0]));
    	printf("%d\n", ans);
    	return 0;
    }

    for(i = 0; i < n; i++)
    {
    	for(j = 0; j < n; j++)
    	{
    		if(i == j)
    			continue;
    		maxim = INT_MAX;

    		for(k = 0; k < m; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k]));
    		normal[i][j] = maxim;

    		maxim = INT_MAX;
    		for(k = 0; k < m - 1; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k + 1]));
    		firstLast[j][i] = maxim;
    		//cout << i << ' ' << j << ' ' << normal[i][j] << ' ' << firstLast[j][i] << endl;
    	}
    }
    int ans = 0;
    for(i = 0; i < n; i++)
    {
    	first = i;

    	ans = max(ans, solve(1 << i, i));
    }

    cout << ans;

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll       long long

#define  sci(x)   scanf("%d", &x)
#define  scl(x)   scanf("%lld", &x)
#define  scd(x)   scanf("%lf", &x)

#define  pfi(x)   printf("%d", x)
#define  pfl(x)   printf("%lld", x)
#define  pfd(x)   printf("%lf", x)
#define  pfc(x)   printf("Case %d: ", x++)
#define  ps       printf(" ")
#define  pn       printf("\n")

#define  pb       push_back
#define  ppb      pop_back
#define  pf       push_front
#define  ppf      pop_front
#define  In       insert
#define  All(a)   a.begin(), a.end()

int data[16][10005];
int normal[16][16], firstLast[16][16], n, first;
int dp[16][1 << 16][16];

int solve(int mask, int from)
{
	if(__builtin_popcount(mask) == n)
	{
		//cout << first << ' ' << from << ' ' << firstLast[first][from] << endl;
		return firstLast[first][from];
	}
	if(dp[first][mask][from] != -1)
		return dp[first][mask][from];
	int ret = 0, p;
	for(int i = 0; i < n; i++)
		if(!(mask & (1 << i)))
		{
			p = solve(mask | (1 << i), i);
			//cout << from << ' ' << i << ' '<< normal[from][i] << ' '<< p<< endl;
			ret = max(ret, min(normal[from][i], p));
		}

	//cout << mask << ' ' << ret << endl;
	return dp[first][mask][from] = ret;
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    memset(dp, -1, sizeof dp);
    int m;
    sci(n), sci(m);

    int i, j, k, maxim;

    for(i = 0; i < n; i++)
    	for(j = 0; j < m; j++)
    		sci(data[i][j]);

    /*if(n == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < m - 1; i++)
    		ans = min(ans, abs(data[0][i] - data[0][i + 1]));
    	printf("%d\n", ans);
    	return 0;
    }
    if(m == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < n - 1; i++)
    		ans = min(ans, abs(data[i][0] - data[i + 1][0]));
    	printf("%d\n", ans);
    	return 0;
    }*/

    for(i = 0; i < n; i++)
    {
    	for(j = 0; j < n; j++)
    	{
    		/*if(i == j)
    			continue;*/
    		maxim = INT_MAX;

    		for(k = 0; k < m; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k]));
    		normal[i][j] = maxim;

    		maxim = INT_MAX;
    		for(k = 0; k < m - 1; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k + 1]));
    		firstLast[j][i] = maxim;
    		//cout << i << ' ' << j << ' ' << normal[i][j] << ' ' << firstLast[j][i] << endl;
    	}
    }
    int ans = 0;
    for(i = 0; i < n; i++)
    {
    	first = i;
    	ans = max(ans, solve(1 << i, i));
    }

    cout << ans;

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll       long long

#define  sci(x)   scanf("%d", &x)
#define  scl(x)   scanf("%lld", &x)
#define  scd(x)   scanf("%lf", &x)

#define  pfi(x)   printf("%d", x)
#define  pfl(x)   printf("%lld", x)
#define  pfd(x)   printf("%lf", x)
#define  pfc(x)   printf("Case %d: ", x++)
#define  ps       printf(" ")
#define  pn       printf("\n")

#define  pb       push_back
#define  ppb      pop_back
#define  pf       push_front
#define  ppf      pop_front
#define  In       insert
#define  All(a)   a.begin(), a.end()

int data[16][10005];
int normal[16][16], firstLast[16][16], n, first;
int dp[16][1 << 16];

int solve(int mask, int from)
{
	if(__builtin_popcount(mask) == n)
	{
		//cout << first << ' ' << from << ' ' << firstLast[first][from] << endl;
		return firstLast[first][from];
	}
	if(dp[first][mask] != -1)
		return dp[first][mask];
	int ret = 0, p;
	for(int i = 0; i < n; i++)
		if(!(mask & (1 << i)))
		{
			p = solve(mask | (1 << i), i);
			//cout << from << ' ' << i << ' '<< normal[from][i] << ' '<< p<< endl;
			ret = max(ret, min(normal[from][i], p));
		}

	//cout << mask << ' ' << ret << endl;
	return dp[first][mask] = ret;
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    memset(dp, -1, sizeof dp);
    int m;
    sci(n), sci(m);

    int i, j, k, maxim;

    for(i = 0; i < n; i++)
    	for(j = 0; j < m; j++)
    		sci(data[i][j]);

    /*if(n == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < m - 1; i++)
    		ans = min(ans, abs(data[0][i] - data[0][i + 1]));
    	printf("%d\n", ans);
    	return 0;
    }
    if(m == 1)
    {
    	int ans = INT_MAX;
    	for(i = 0; i < n - 1; i++)
    		ans = min(ans, abs(data[i][0] - data[i + 1][0]));
    	printf("%d\n", ans);
    	return 0;
    }*/

    for(i = 0; i < n; i++)
    {
    	for(j = 0; j < n; j++)
    	{
    		/*if(i == j)
    			continue;*/
    		maxim = INT_MAX;

    		for(k = 0; k < m; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k]));
    		normal[i][j] = maxim;

    		maxim = INT_MAX;
    		for(k = 0; k < m - 1; k++)
    			maxim = min(maxim, abs(data[i][k] - data[j][k + 1]));
    		firstLast[j][i] = maxim;
    		//cout << i << ' ' << j << ' ' << normal[i][j] << ' ' << firstLast[j][i] << endl;
    	}
    }
    int ans = 0;
    for(i = 0; i < n; i++)
    {
    	first = i;
    	ans = max(ans, solve(1 << i, i));
    }

    cout << ans;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector<int> visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        if(n==l){
                            dp[l][s][e] = min(min_first_last_diff[s][e],min_Consecutive_diff[s][e]);
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        visited[2][s][e].push_back(s);
                        visited[2][s][e].push_back(e);
                    }else{
                        int index_max = 0;
                        int max_value = 0;
                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(n==l){
                                    val = min(val,min_first_last_diff[s][e]);
                                }
                                if(val > max_value){
                                    max_value = val;
                                    index_max = k;
                                }
                            }

                        }

                        dp[l][s][e] = max_value;
                        visited[l][s][e] = visited[l-1][index_max][e];
                        visited[l][s][e].insert(visited[l][s][e].begin(),s);

//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector<int> visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        if(n==l){
                            dp[l][s][e] = min(min_first_last_diff[s][e],min_Consecutive_diff[s][e]);
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        visited[2][s][e].push_back(s);
                        visited[2][s][e].push_back(e);
                    }else{
                        int index_max = 0;
                        int max_value = 0;

                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(n==l){
                                    val = min(val,min_first_last_diff[s][e]);
                                }
                                if(val > max_value){
                                    max_value = val;
                                    index_max = k;
                                }
                            }

                        }

                        int count = 0;
                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(val == max_value){
                                    count += 1;
                                }
                            }

                        }
                        dp[l][s][e] = max_value;
                        visited[l][s][e] = visited[l-1][index_max][e];
                        visited[l][s][e].insert(visited[l][s][e].begin(),s);
                        if(count > 1){
                            visited[l][s][e].erase(remove(visited[l][s][e].begin(), visited[l][s][e].end(), index_max), visited[l][s][e].end());
                        }
//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector< vector<int> > visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        vector <int> temp;
                        if(n==l){
                            dp[l][s][e] = min(min_first_last_diff[s][e],min_Consecutive_diff[s][e]);
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        temp.push_back(s);
                        temp.push_back(e);
                        visited[2][s][e].push_back(temp);
                    }else{
                        int max_value = 0;

                        for(int k=0; k<n; k++){
                            for(int j=0; j<visited[l-1][k][e].size() ; j++){

                                if( std::find(visited[l-1][k][e][j].begin(), visited[l-1][k][e][j].end(), s) == visited[l-1][k][e][j].end()) {
    //                                 cout << "DCsfsfcff " << k << endl;
                                    int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                    if(n==l){
                                        val = min(val,min_first_last_diff[s][e]);
                                    }
                                    if(val > max_value){
                                        max_value = val;
                                    }
                                }

                            }
                        }

                        dp[l][s][e] = max_value;

                        vector<int> mins;
                        for(int k=0; k<n; k++){
                            for(int j=0; j<visited[l-1][k][e].size() ; j++){
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if( std::find(visited[l-1][k][e][j].begin(), visited[l-1][k][e][j].end(), s) == visited[l-1][k][e][j].end()) {
                                    if(val == max_value){
                                        mins.push_back(k);
                                    }
                                }

                            }
                        }

                        for(int i=0; i<mins.size(); i++){
                            for(int j=0; j<visited[l-1][mins[i]][e].size(); j++){

                                vector<int> temp = visited[l-1][mins[i]][e][j];
                                temp.insert(temp.begin(),s);
                                visited[l][s][e].push_back(temp);
                            }
                        }

//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][1 << 17 + 1];

int find_max(int start,int now,int mask){
    if(__builtin_popcount(mask) == n){
        return min_first_last_diff[start][now];
    }
    if(dp[start][now][mask]!=-1){
        return dp[start][now][mask];
    }
    int mx = 0;
    for(int i=0; i<n; i++){
        if(!(mask & (1 << i))){
            int t = find_max(start,i,mask | (1 << i));
            int val = min(t,min_Consecutive_diff[i][now]);
            mx = max(mx,val);
        }
    }
    dp[start][now][mask] = mx;
    return mx;

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

    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<(1<< n + 1); k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9 + 5;
            for(int k=0; k<m; k++){
                mn_con = min(mn_con,abs(arr[i][k]-arr[j][k]));
            }
            min_Consecutive_diff[i][j] = mn_con;

            int mn_fl = 1e9 + 5;
            for(int k=0; k<m-1; k++){
                mn_fl = min(mn_fl, abs(arr[j][k]-arr[i][k+1]));
            }
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;
    for(int j=0; j<n ; j++){
        int temp = find_max(j,j,(1 << j));
        mx = max(mx,temp);
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,i,end,temp);
            if(n==15){
                cout << l << " : " << t << " ";
            }
            int val = min(t,min_Consecutive_diff[start][i]);
            mx = max(mx,val);
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int temp = find_max(n,j,i,v);
                int val = min(temp,min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }
    cout << endl;
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int now,vector<int> visited){
    if(l==1){
        return min_first_last_diff[start][now];
    }
    if(dp[l][start][now]!=-1){
        return dp[l][start][now];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,start,i,temp);
            int val = min(t,min_Consecutive_diff[i][now]);
            mx = max(mx,val);
        }

    }
    dp[l][start][now] = mx;
    return mx;

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

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){

        vector<int> v;
        v.push_back(j);
        int temp = find_max(n,j,j,v);
        mx = max(mx,temp);

    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector<int> visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        if(n==l){
                            dp[l][s][e] = min_first_last_diff[s][e];
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        visited[2][s][e].push_back(s);
                        visited[2][s][e].push_back(e);
                    }else{
                        int index_max = 0;
                        int max_value = 0;
                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(n==l){
                                    val = min(val,min_first_last_diff[s][e]);
                                }
                                if(val > max_value){
                                    max_value = val;
                                    index_max = k;
                                }
                            }

                        }

                        dp[l][s][e] = max_value;
                        visited[l][s][e] = visited[l-1][index_max][e];
                        visited[l][s][e].insert(visited[l][s][e].begin(),s);

//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,set<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(visited.count(i)==0){
            set<int> temp = visited;
            temp.insert(i);
            int val = min(find_max(l-1,i,end,temp),min_Consecutive_diff[start][i]);
            if(val>mx){
                mx = val;
            }
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                set<int> v;
                v.insert(i);
                v.insert(j);
                int val = min(find_max(n,j,i,v),min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }

    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector<int> visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        if(n==l){
                            dp[l][s][e] = min(min_first_last_diff[s][e],min_Consecutive_diff[s][e]);
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        visited[2][s][e].push_back(s);
                        visited[2][s][e].push_back(e);
                    }else{
                        int index_max = 0;
                        int max_value = 0;
                        bool multiple = false;
                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(n==l){
                                    val = min(val,min_first_last_diff[s][e]);
                                }
                                if(val == max_value){
                                    multiple =true;
                                }
                                if(val > max_value){
                                    max_value = val;
                                    index_max = k;
                                }
                            }

                        }

                        dp[l][s][e] = max_value;
                        visited[l][s][e] = visited[l-1][index_max][e];
                        visited[l][s][e].insert(visited[l][s][e].begin(),s);
                        if(multiple){
                            visited[l][s][e].erase(remove(visited[l][s][e].begin(), visited[l][s][e].end(), index_max), visited[l][s][e].end());
                        }
//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int temp = find_max(l-1,i,end,temp);
            if(n==15){
                cout << temp << " ";
            }
            int val = min(temp,min_Consecutive_diff[start][i]);
            mx = max(mx,val);
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int temp = find_max(n,j,i,v);
                int val = min(temp,min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }
    cout << endl;
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int val = min(find_max(l-1,i,end,temp),min_Consecutive_diff[start][i]);
            mx = max(mx,val);
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int temp = find_max(n,j,i,v);
                int val = min(temp,min_first_last_diff[j][i]);
                if(n==15){
                    cout << temp << " ";
                }
                if(val>mx){
                    mx = val;
                }
            }

        }
    }
    cout << endl;
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,i,end,temp);
            if(n==15){
                cout << t << " ";
            }
            int val = min(t,min_Consecutive_diff[start][i]);
            mx = max(mx,val);
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int temp = find_max(n,j,i,v);
                int val = min(temp,min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }
    cout << endl;
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int now,vector<int> visited){
    if(l==1){
        return min_first_last_diff[start][now];
    }
    if(dp[l][start][now]!=-1){
        return dp[l][start][now];
    }
    int mx = 0;
    for(int i=0; i<n; i++){
        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,start,i,temp);
            int val = min(t,min_Consecutive_diff[i][now]);
            mx = max(mx,val);
        }
    }
    dp[l][start][now] = mx;
    return mx;

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

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9 + 5;
            for(int k=0; k<m; k++){
                mn_con = min(mn_con,abs(arr[i][k]-arr[j][k]));
            }
            min_Consecutive_diff[i][j] = mn_con;

            int mn_fl = 1e9 + 5;
            for(int k=0; k<m-1; k++){
                mn_fl = min(mn_fl, abs(arr[j][k]-arr[i][k+1]));
            }
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;
    for(int j=0; j<n ; j++){
        vector<int> v;
        v.push_back(j);
        int temp = find_max(n,j,j,v);
        mx = max(mx,temp);
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int now,vector<int> visited){
    if(l==1){
        return min_first_last_diff[start][now];
    }
    if(dp[l][start][now]!=-1){
        return dp[l][start][now];
    }
    int mx = 0;
    for(int i=0; i<n; i++){
        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,start,i,temp);
            int val = min(t,min_Consecutive_diff[i][now]);
            mx = max(mx,val);
        }
    }
    dp[l][start][now] = mx;
    return mx;

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

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9 + 5;
            for(int k=0; k<m; k++){
                mn_con = min(mn_con,abs(arr[i][k]-arr[j][k]));
            }
            min_Consecutive_diff[i][j] = mn_con;

            int mn_fl = 1e9 + 5;
            for(int k=0; k<m; k++){
                mn_fl = min(mn_fl, abs(arr[j][k]-arr[i][k+1]));
            }
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;
    for(int j=0; j<n ; j++){
        vector<int> v;
        v.push_back(j);
        int temp = find_max(n,j,j,v);
        mx = max(mx,temp);
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int dp[17][16][16];

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
//             cout << val << endl;
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }
    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    vector<int> visited[n+1][n][n];

    for(int l=2; l<=n; l++){
        for(int s=0; s<n; s++){
            for(int e=0; e<n; e++){
                if(s!=e){
                    if(l==2){
                        if(n==l){
                            dp[l][s][e] = min_first_last_diff[s][e];
                        }else{
                            dp[l][s][e] = min_Consecutive_diff[s][e];
                        }
//                         cout << s << " " << e << " " << dp[l][s][e] << endl;
                        visited[2][s][e].push_back(s);
                        visited[2][s][e].push_back(e);
                    }else{
                        int index_max = 0;
                        int max_value = 0;
                        for(int k=0; k<n; k++){
                            if(visited[l-1][k][e].size() != 0 && std::find(visited[l-1][k][e].begin(), visited[l-1][k][e].end(), s) == visited[l-1][k][e].end()) {
//                                 cout << "DCsfsfcff " << k << endl;
                                int val = min(dp[l-1][k][e],min_Consecutive_diff[s][k]);
                                if(n==l){
                                    val = min(val,min_first_last_diff[s][e]);
                                }
                                if(val > max_value){
                                    max_value = val;
                                    index_max = k;
                                }
                            }

                        }

                        dp[l][s][e] = max_value;
                        visited[l][s][e] = visited[l-1][index_max][e];
                        visited[l][s][e].insert(visited[l][s][e].begin(),s);

//                         cout << l << " " << s << " " << e << endl;
//                         for(int i=0 ; i<visited[l][s][e].size(); i++){
//                             cout << visited[l][s][e][i] << " " ;
//                         }
//                         cout << endl << dp[l][s][e] << endl;

                    }

                }
            }
        }
    }

    int mx = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n ; j++){
            if(dp[n][i][j] > mx){
                mx = dp[n][i][j];
            }
        }
    }
    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int val = min(find_max(l-1,i,end,temp),min_Consecutive_diff[start][i]);
            if(val>mx){
                mx = val;
            }
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int val = min(find_max(n,j,i,v),min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }

    cout << mx << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][16];

int find_max(int l,int start,int end,vector<int> visited){
    if(l==2){
        return min_Consecutive_diff[start][end];
    }
    if(dp[l][start][end]!=-1){
        return dp[l][start][end];
    }
    int mx = 0;
    for(int i=0; i<n; i++){

        if(find(visited.begin(),visited.end(),i)==visited.end()){
            vector<int> temp = visited;
            temp.push_back(i);
            int t = find_max(l-1,i,end,temp);
            if(n==15){
                cout << l << " : " t << " ";
            }
            int val = min(t,min_Consecutive_diff[start][i]);
            mx = max(mx,val);
        }

    }
    dp[l][start][end] = mx;
    return mx;

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

    if(n==1){
        int mn = 1e9+1;
        for(int i=0; i<m-1; i++){
            int val = abs(arr[0][i+1]-arr[0][i]);
            if(val < mn){
                mn = val;
            }
        }
        cout << mn << endl;
        return 0;

    }

    for(int i=0; i<=n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<n; k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9+1;
            int mn_fl = 1e9+1;
            for(int k=0; k<m; k++){
                int val_con = abs(arr[i][k]-arr[j][k]);
                if(k!=m-1){
                    int val_fl = abs(arr[j][k]-arr[i][k+1]);
                    if(val_fl < mn_fl){
                        mn_fl = val_fl;
                    }
                }
                if(val_con < mn_con){
                    mn_con = val_con;
                }
            }
            min_Consecutive_diff[i][j] = mn_con;
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;

    for(int j=0; j<n ; j++){
        for(int i=0; i<n; i++){
            if(i!=j){
                vector<int> v;
                v.push_back(i);
                v.push_back(j);
                int temp = find_max(n,j,i,v);
                int val = min(temp,min_first_last_diff[j][i]);
                if(val>mx){
                    mx = val;
                }
            }

        }
    }
    cout << endl;
    cout << mx << endl;
    return 0;
}


#include <iostream>

using namespace std;

int arr[16][10000];
int min_Consecutive_diff[16][16];
int min_first_last_diff[16][16];
int n;
int dp[17][16][(1 << 17) + 1];

int find_max(int start,int now,int mask){
    if(__builtin_popcount(mask) == n){
        return min_first_last_diff[start][now];
    }
    if(dp[start][now][mask]!=-1){
        return dp[start][now][mask];
    }
    int mx = 0;
    for(int i=0; i<n; i++){
        if(!(mask & (1 << i))){
            int t = find_max(start,i,mask | (1 << i));
            int val = min(t,min_Consecutive_diff[i][now]);
            mx = max(mx,val);
        }
    }
    dp[start][now][mask] = mx;
    return mx;

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

    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            for(int k=0; k<((1<< n) + 1); k++){
                dp[i][j][k] = -1;
            }
        }
    }

    for(int i=0 ; i<n; i++){
        for(int j=0 ; j<n ; j++){
            int mn_con = 1e9 + 5;
            for(int k=0; k<m; k++){
                mn_con = min(mn_con,abs(arr[i][k]-arr[j][k]));
            }
            min_Consecutive_diff[i][j] = mn_con;

            int mn_fl = 1e9 + 5;
            for(int k=0; k<m-1; k++){
                mn_fl = min(mn_fl, abs(arr[j][k]-arr[i][k+1]));
            }
            min_first_last_diff[i][j] = mn_fl;
        }
    }

    int mx = 0;
    for(int j=0; j<n ; j++){
        int temp = find_max(j,j,(1 << j));
        mx = max(mx,temp);
    }
    cout << mx << endl;
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
vector<vector<int> > graf;
vector<int> visited;
bool t;
void dfs(int tr)
{
    if(visited[tr]==n)
        t=true;
    for(auto p:graf[tr])
    {
        if(visited[p]==0)
        {
            visited[p]=visited[tr]+1;
            dfs(p);
            visited[p]=0;
        }
    }
}
bool test(int k)
{
    graf.resize(0);
    graf.resize(n);
    visited.clear();
    for(int i=0;i<n;i++)
        graf[i].clear();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                graf[i].pb(j);
                graf[j].pb(i);
            }
        }
    }
    t=false;
    for(int i=0;i<n;i++)
    {
        visited[i]=1;
        dfs(i);
        if(t)
            return true;
        visited[i]=0;
    }
    return false;
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    visited.resize(n);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
vector<vector<int> > graf;
vector<vector<bool> > moze;
vector<int> visited;
vector<int> en;
void dfs(int tr)
{
    if(visited[tr]==n)
        en.pb(tr);
    for(auto p:graf[tr])
    {
        if(visited[p]==0)
        {
            visited[p]=visited[tr]+1;
            dfs(p);
            visited[p]=0;
        }
    }
}
bool test(int k)
{
    graf.resize(0);
    graf.resize(n);
    visited.clear();
    for(int i=0;i<n;i++)
        graf[i].clear();
    for(int i=0;i<n;i++)
        fill(all(moze[i]),false);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m-1;l++)
            {
                if(abs(mat[j][l]-mat[i][l+1])<k){
                    test=false;
                    break;
                }
            }
            if(test)
                moze[i][j]=true;
            else
                moze[i][j]=false;
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                graf[i].pb(j);
                graf[j].pb(i);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        en.clear();
        visited[i]=1;
        dfs(i);
        for(auto p:en)
        {
            if(moze[i][p]||moze[p][i])
                return true;
        }
        visited[i]=0;
    }
    return false;
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    moze.resize(n,vector<bool>(m));
    visited.resize(n);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
vector<vector<int> > graf;
vector<int> visited;
vector<int> en;
void dfs(int tr)
{
    if(visited[tr]==n)
        en.pb(tr);
    for(auto p:graf[tr])
    {
        if(visited[p]==0)
        {
            visited[p]=visited[tr]+1;
            dfs(p);
            visited[p]=0;
        }
    }
}
bool test(int k)
{
    graf.resize(0);
    graf.resize(n);
    visited.clear();
    for(int i=0;i<n;i++)
        graf[i].clear();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                graf[i].pb(j);
                graf[j].pb(i);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        en.clear();
        visited[i]=1;
        dfs(i);
        for(auto p:en)
        {
            bool test=true;
            for(int j=0;j<m-1;j++)
            {
                if(abs(mat[p][j]-mat[i][j+1])<k){
                    test=false;
                    break;
                }
            }
            if(test)
                return true;
        }
        visited[i]=0;
    }
    return false;
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    visited.resize(n);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
bool adj[16][16];
vector<vector<bool> > moze;
bool check_using_dp(){
        bool dp[n][1<<n][n];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<(1<<n);j++)
                for(int k=0;k<n;k++)
                    dp[i][j][k]=false;
        }
        for(int i=0; i<n; i++)
            dp[i][1<<i][i]=true;
        for(int i=0; i<(1<<n); i++){
            for(int j=0; j<n; j++)
                if(i&(1<<j)){
                    for(int k=0; k<n; k++){
                        if((i&(1<<k)) && adj[k][j] && k!=j)
                        for(int l=0;l<n;l++)
                            if( (i&(1<<k)) && adj[k][j] && k!=j && dp[k][i^(1<<j)][l]){
                                dp[j][i][l]=true;
                            }
                    }
                }
        }
        for(int i=0; i<n; i++)
            for(int l=0;l<n;l++)
        {
            if(dp[i][(1<<n)-1][l])
            if(moze[l][i]||moze[i][l])
                return true;
        }
        return false;
    }
bool test(int k)
{
    //printf("Testiram %i\n",k);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            adj[i][j]=false;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                //printf("%i %i\n",i,j);
                adj[i][j]=true;
                adj[j][i]=true;
            }
        }
    }
    for(int i=0;i<n;i++)
        fill(all(moze[i]),false);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m-1;l++)
            {
                if(abs(mat[j][l]-mat[i][l+1])<k){
                    test=false;
                    break;
                }
            }
            if(test)
                moze[i][j]=true;
            else
                moze[i][j]=false;
        }
    }
    return check_using_dp();
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    moze.resize(n,vector<bool>(m));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
bool adj[16][16];
vector<vector<bool> > moze;
bool check_using_dp(){
        set<int> dp[n][1<<n];
        for(int i=0; i<n; i++)
            dp[i][1<<i].insert(i);
        for(int i=0; i<(1<<n); i++){
            for(int j=0; j<n; j++)
                if(i&(1<<j)){
                    for(int k=0; k<n; k++){
                        if( (i&(1<<k)) && adj[k][j] && k!=j && dp[k][i^(1<<j)].size()){
                            for(auto p:dp[k][i^(1<<j)])
                                dp[j][i].insert(p);
                            break;
                        }
                    }
                }
        }
        for(int i=0; i<n; i++)
            for(auto p:dp[i][(1<<n)-1])
        {
            if(moze[p][i]||moze[i][p])
                return true;
        }
        return false;
    }
bool test(int k)
{
    //printf("Testiram %i\n",k);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            adj[i][j]=false;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                //printf("%i %i\n",i,j);
                adj[i][j]=true;
                adj[j][i]=true;
            }
        }
    }
    for(int i=0;i<n;i++)
        fill(all(moze[i]),false);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m-1;l++)
            {
                if(abs(mat[j][l]-mat[i][l+1])<k){
                    test=false;
                    break;
                }
            }
            if(test)
                moze[i][j]=true;
            else
                moze[i][j]=false;
        }
    }
    return check_using_dp();
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    moze.resize(n,vector<bool>(m));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define pb push_back
#define sz(x) (int)(x).size()
#define mp make_pair
#define f first
#define s second
#define all(x) x.begin(), x.end()

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; ///find_by_order(),order_of_key()
template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) { os << '{' << a.f << ", " << a.s << '}'; return os; }
template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	os << '{';
	for(int i=0;i<sz(a);i++)
	{
		if(i>0&&i<sz(a)-1)
			os << ", ";
		os << a[i];
	}
	os << '}';
    return os;
}
int n,m;
vector<vector<int> > mat;
vector<vector<int> > graf;
vector<int> visited;
set<int> en;
void dfs(int tr)
{
    if(visited[tr]==n)
        en.insert(tr);
    for(auto p:graf[tr])
    {
        if(visited[p]==0)
        {
            visited[p]=visited[tr]+1;
            dfs(p);
            visited[p]=0;
        }
    }
}
bool test(int k)
{
    graf.resize(0);
    graf.resize(n);
    visited.clear();
    for(int i=0;i<n;i++)
        graf[i].clear();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            bool test=true;
            for(int l=0;l<m;l++)
            {
                int d=abs(mat[i][l]-mat[j][l]);
                if(d<k)
                {
                    test=false;
                    break;
                }
            }
            if(test)
            {
                graf[i].pb(j);
                graf[j].pb(i);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        en.clear();
        visited[i]=1;
        dfs(i);
        for(auto p:en)
        {
            bool test=true;
            for(int j=0;j<m-1;j++)
            {
                if(abs(mat[p][j]-mat[i][j+1])<k){
                    test=false;
                    break;
                }
            }
            if(test)
                return true;
        }
        visited[i]=0;
    }
    return false;
}
int main()
{
    scanf("%i %i",&n,&m);
    mat.resize(n,vector<int>(m));
    visited.resize(n);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%i",&mat[i][j]);
        }
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int m=(l+r+1)>>1;
        if(test(m))
        {
            l=m;
        }
        else
        {
            r=m-1;
        }
    }
    printf("%i\n",l);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 16;
const int maxm = 10000;
//以这个起点出发求状压dp，dp[S][i] 代表最后到达的点是i，状态是S
int a[maxn][maxm], mi[maxn][maxn], dp[1<<maxn][maxn];
int n, m;
int main(){
    scanf("%d%d", &n,&m);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            scanf("%d", &a[i][j]);
    for(int i = 0; i < n; i++){
        for(int j = i+1; j < n; j++){
            int minn = 0x3f3f3f3f;
            for(int k = 0; k < m; k++){
                minn = min(minn, abs(a[i][k] - a[j][k]));
            }
            mi[i][j] = minn;
            mi[j][i] = minn;
        }
    }
    //dp
    int ans = 0;
    for(int st = 0; st < n; st++){
        for(int mask = 0; mask < 1 << n; mask++)
            fill_n(dp[mask], n, 0);
        dp[1 << st][st] = 0x3f3f3f3f;
        for(int mask = 0; mask < 1 << n; mask++){
            for(int en = 0; en < n; en++){
                if(dp[mask][en])
                for(int i = 0; i < n; i++){
                    if(!(mask & 1 << i))
                        dp[mask | 1 << i][i] = max(dp[mask | 1 << i][i], min(dp[mask][en], mi[en][i]));
                }
            }
            for(int en = 0; en < n; en++){
                int minn = dp[(1 << n) - 1][en];
                for(int j = 0; j+1 < m; j++){
                    minn = min(minn, abs(a[en][j] - a[st][j+1]));
                }
                ans = max(ans, minn);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 18;
const int maxm = 10003;
//以这个起点出发求状压dp，dp[S][i] 代表最后到达的点是i，状态是S
int a[maxn][maxm], mi[maxn][maxn], dp[1<<maxn][maxn];
int n, m;
int main(){
    scanf("%d%d", &n,&m);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            scanf("%d", &a[i][j]);
    for(int i = 0; i < n; i++){
        for(int j = i+1; j < n; j++){
            int minn = 0x3f3f3f3f;
            for(int k = 0; k < m; k++){
                minn = min(minn, abs(a[i][k] - a[j][k]));
            }
            mi[i][j] = minn;
            mi[j][i] = minn;
        }
    }
    //dp
    int ans = 0;
    for(int st = 0; st < n; st++){
        for(int mask = 0; mask < 1 << n; mask++)
            fill_n(dp[mask], n, 0);
        dp[1 << st][st] = 0x3f3f3f3f;
        for(int mask = 0; mask < 1 << n; mask++){
            for(int en = 0; en < n; en++){
                if(dp[mask][en])
                for(int i = 0; i < n; i++){
                    if(!(mask & 1 << i))
                        dp[mask | 1 << i][i] = max(dp[mask | 1 << i][i], min(dp[mask][en], mi[en][i]));
                }
            }
            for(int en = 0; en < n; en++){
                int minn = dp[(1 << n) - 1][en];
                for(int j = 0; j+1 < m; j++){
                    minn = min(minn, abs(a[en][j] - a[st][j+1]));
                }
                ans = max(ans, minn);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 18;
const int maxm = 100 * 100 + 13;
const int INF = 1e9;
int dp[1<<maxn][maxn];
int a[maxn][maxm];
int n, m, mn1[maxn][maxn], mn2[maxn][maxn];
int cal(int mask, int en){
    if(dp[mask][en] != -1) return dp[mask][en];
    dp[mask][en] = 0;
    for(int st = 0; st < n; st++){
        if(st != en && ((mask >> st) & 1))
            dp[mask][en] = max(dp[mask][en], min(mn1[st][en], cal(mask ^ (1<<en), st)));
    }
    return dp[mask][en];
}
int main(){
    scanf("%d%d", &n,&m);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            scanf("%d", &a[i][j]);
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            int val = INF;
            for(int k = 0; k < m; k++){
                val = min(val, abs(a[i][k] - a[j][k]));
            }
            mn1[i][j] = val;
            val = INF;
            for(int k = 0; k < m-1; k++){
                val = min(val, abs(a[i][k] - a[j][k+1]));
            }
            mn2[i][j] = val;
        }
    }
    int ans = 0;
    for(int i = 0; i < n; i++){
        memset(dp, -1, sizeof(dp));
        for(int j = 0; j < n; j++){
            dp[1<<j][j] = (j == i ? INF : 0);
        }
        for(int j = 0; j < n; j++){
            ans = max(ans, min(mn2[j][i], cal((1<<n)-1, j)));
        }
    }
    printf("%d\n", ans);
}


#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+10;
const int inf=0x3f3f3f3f;
int n,m,p;
int mi[20][20],a[20][N],mi1[20][20];
int dp[1<<17][20];
int dfs(int s,int pre){
    if (~dp[s][pre])return dp[s][pre];
    int f=0;
    for (int i=1;i<=n;i++){
        if (i==pre||(s&(1<<(i-1))))continue;
        f=1;
        dp[s][pre]=max(dp[s][pre],min(mi[pre][i],dfs(s^(1<<(i-1)),i)));
    }
    if (!f)return dp[s][pre]=mi1[pre][p];
    return dp[s][pre];
}
signed main(){
    cin>>n>>m;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            scanf("%lld",&a[i][j]);
        }
    }
    memset(mi,inf,sizeof mi);
    memset(mi1,inf,sizeof mi1);
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            for (int k=1;k<=m;k++){//同一列i,j行
                mi[i][j]=min(mi[i][j],abs(a[i][k]-a[j][k]));
            }
            for (int k=1;k<m;k++){//相邻行 ij列为底和顶
                mi1[i][j]=min(mi1[i][j],abs(a[i][k]-a[j][k+1]));
            }
        }
    }
    int ans=0;
    for (int i=1;i<=n;i++){
        memset(dp,-1,sizeof dp);
        p=i;
        dfs((1<<(i-1)),i);
        ans=max(ans,dp[(1<<(i-1))][i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+10;
const int inf=0x3f3f3f3f;
int n,m,p;
int mi[20][20],a[20][N],mi1[20][20];
int dp[1<<17][20];
int dfs(int s,int pre){
    if (~dp[s][pre])return dp[s][pre];
    int f=0;
    for (int i=1;i<=n;i++){
        if (i==pre||(s&(1<<(i-1))))continue;
        f=1;
        dp[s][pre]=max(dp[s][pre],min(mi[pre][i],dfs(s^(1<<(i-1)),i)));
    }
    if (!f)return mi1[pre][p];
    return dp[s][pre];
}
signed main(){
    cin>>n>>m;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            scanf("%lld",&a[i][j]);
        }
    }
    memset(mi,inf,sizeof mi);
    memset(mi1,inf,sizeof mi1);
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            for (int k=1;k<=m;k++){//同一列i,j行
                mi[i][j]=min(mi[i][j],abs(a[i][k]-a[j][k]));
            }
            for (int k=1;k<m;k++){//相邻行 ij列为底和顶
                mi1[i][j]=min(mi1[i][j],abs(a[i][k]-a[j][k+1]));
            }
        }
    }
    int ans=0;
    for (int i=1;i<=n;i++){
        memset(dp,-1,sizeof dp);
        p=i;
        dfs((1<<(i-1)),i);
        ans=max(ans,dp[(1<<(i-1))][i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N=17,M=1e4+5;
int n,m,inf,max_statue,ans;
int a[N][M],w[N][N],w2[N][N],f[1<<N][N];
int main(){
	scanf("%d%d",&n,&m);
	for (register int i=0; i<n; ++i)
	for (register int j=1; j<=m; ++j) scanf("%d",&a[i][j]);
	inf=1e9;
	for (register int i=0; i<n; ++i)
	for (register int j=0; j<n; ++j)
	{
		w[i][j]=w2[i][j]=inf;
		for (register int k=1; k<=m; ++k) w[i][j]=min(w[i][j],abs(a[i][k]-a[j][k]));
		for (register int k=2; k<=m; ++k) w2[i][j]=min(w2[i][j],abs(a[i][k]-a[j][k-1]));
		//第一行为i，最后一行为j
	}
//	for (register int i=0; i<n; ++i)
//	for (register int j=0; j<n; ++j) printf("i=%d j=%d w2[i][j]=%d\n",i,j,w2[i][j]);
	ans=0;
	max_statue=(1<<n)-1;
	for (register int k=0; k<n; ++k)
	{
		memset(f,0,sizeof(f));
		f[1<<k][k]=inf;
		for (register int p=0; p<=max_statue; ++p)
		for (register int i=0; i<n; ++i)
		if ((1<<i)&p)
		{
			for (register int j=0; j<n; ++j)
			if (!((1<<j)&p)) f[p|(1<<j)][j]=max(f[p|(1<<j)][j],min(f[p][i],w[i][j]));
		}
		for (register int i=0; i<n; ++i) ans=max(ans,min(f[max_statue][i],w2[k][i]));
	}
	printf("%d\n",ans);
return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N=17;
int n,m,inf,max_statue,ans;
int a[N][N],w[N][N],w2[N][N],f[1<<N][N];
int main(){
	scanf("%d%d",&n,&m);
	for (register int i=0; i<n; ++i)
	for (register int j=1; j<=m; ++j) scanf("%d",&a[i][j]);
	inf=1e9;
	for (register int i=0; i<n; ++i)
	for (register int j=0; j<n; ++j)
	{
		w[i][j]=w2[i][j]=inf;
		for (register int k=1; k<=m; ++k) w[i][j]=min(w[i][j],abs(a[i][k]-a[j][k]));
		for (register int k=2; k<=m; ++k) w2[i][j]=min(w2[i][j],abs(a[i][k]-a[j][k-1]));
		//第一行为i，最后一行为j
	}
//	for (register int i=0; i<n; ++i)
//	for (register int j=0; j<n; ++j) printf("i=%d j=%d w2[i][j]=%d\n",i,j,w2[i][j]);
	ans=0;
	max_statue=(1<<n)-1;
	for (register int k=0; k<n; ++k)
	{
		memset(f,0,sizeof(f));
		f[1<<k][k]=inf;
		for (register int p=0; p<=max_statue; ++p)
		for (register int i=0; i<n; ++i)
		if ((1<<i)&p)
		{
			for (register int j=0; j<n; ++j)
			if (!((1<<j)&p)) f[p|(1<<j)][j]=max(f[p|(1<<j)][j],min(f[p][i],w[i][j]));
		}
		for (register int i=0; i<n; ++i) ans=max(ans,min(f[max_statue][i],w2[k][i]));
	}
	printf("%d\n",ans);
return 0;
}