#include <bits/stdc++.h>
using namespace std;
const int N = 510, Node = 5e5 + 10;
struct Line {
  int x, l, r, op;
  bool operator<(const Line &A) const { return x < A.x; }
  Line(int x = 0, int l = 0, int r = 0, int op = 0)
      : x(x), l(l), r(r), op(op) {}
} L[N << 1];
int x[N], y[N], n, m, k;
void Init() {
  scanf("%d%d%d", &n, &m, &k);
  for (int i = 1; i <= k; ++i) scanf("%d%d", &x[i], &y[i]);
}
struct SegmentTree {
  int root, node, son[Node][2], Min[Node], lazy[Node];
  int newnode() {
    ++node;
    son[node][0] = son[node][1] = 0;
    Min[node] = lazy[node] = 0;
    return node;
  }
  void Setlazy(int z, int v) {
    Min[z] += v;
    lazy[z] += v;
  }
  void Update(int z) { Min[z] = min(Min[son[z][0]], Min[son[z][1]]) + lazy[z]; }
  void Add(int &z, int l, int r, int ql, int qr, int v) {
    if (!z) z = newnode();
    if (ql <= l && r <= qr) {
      Setlazy(z, v);
      return;
    }
    int mid = (l + r) >> 1;
    if (ql <= mid) Add(son[z][0], l, mid, ql, qr, v);
    if (qr > mid) Add(son[z][1], mid + 1, r, ql, qr, v);
    Update(z);
  }
  int Queryleft(int z, int l, int r, int slazy) {
    if (!z || l == r) return l;
    int mid = (l + r) >> 1;
    slazy += lazy[z];
    if (Min[son[z][0]] + slazy)
      return Queryleft(son[z][1], mid + 1, r, slazy);
    else
      return Queryleft(son[z][0], l, mid, slazy);
  }
  int Queryright(int z, int l, int r, int slazy) {
    if (!z || l == r) return r;
    int mid = (l + r) >> 1;
    slazy += lazy[z];
    if (Min[son[z][1]] + slazy)
      return Queryright(son[z][0], l, mid, slazy);
    else
      return Queryright(son[z][1], mid + 1, r, slazy);
  }
} St;
bool Can(int t) {
  int top = 0;
  for (int i = 1; i <= k; ++i) {
    int xl = max(1, x[i] - t), xr = min(n, x[i] + t), yl = max(1, y[i] - t),
        yr = min(m, y[i] + t);
    L[++top] = Line(xl, yl, yr, 1);
    L[++top] = Line(xr + 1, yl, yr, -1);
  }
  sort(L + 1, L + top + 1);
  int xl = n + 1, xr = 0, yl = m + 1, yr = 0;
  if (L[1].x > 1) xl = 1, xr = L[1].x - 1, yl = 1, yr = m;
  St.root = St.node = 0;
  for (int i = 1; i <= top;) {
    int pos = i;
    while (L[pos].x == L[i].x && i <= top)
      St.Add(St.root, 1, m, L[i].l, L[i].r, L[i].op), ++i;
    if (L[pos].x <= n && St.Min[St.root] == 0) {
      xl = min(L[pos].x, xl), xr = max(L[pos].x, xr);
      yl = min(yl, St.Queryleft(St.root, 1, m, 0));
      yr = max(yr, St.Queryright(St.root, 1, m, 0));
    }
  }
  if (L[top].x < n) xr = max(xr, n), xl = min(xl, L[top].x), yl = 1, yr = m;
  if ((max(xr - xl, yr - yl) + 1) / 2 <= t)
    return 1;
  else
    return 0;
}
void Solve() {
  int l = 0, r = 1e9 + 1;
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (Can(mid))
      r = mid - 1;
    else
      l = mid + 1;
  }
  printf("%d\n", l);
}
int main() {
  Init();
  Solve();
  return 0;
}
