Language: C++

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>

using namespace std;
using ll = long long;

#define all(c) (c).begin(), (c).end()
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define pb(e) push_back(e)
#define mp(a, b) make_pair(a, b)
#define fr first
#define sc second

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
using P = pair<int, int>;
int n, m, k;

template <>
class hash<P> {
 public:
    size_t operator()(const P &p) const {
        size_t seed = 0;

        seed ^= p.first + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= p.second + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        return seed;
    }
};
template <>
class hash<tuple<P, int>> {
 public:
    size_t operator()(const tuple<P, int> &t) const {
        size_t seed = 0;

        P p = get<0>(t);
        int a = get<1>(t);
        seed ^= p.first + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= p.second + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= a + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        return seed;
    }
};
unordered_set<P> s, t, all;
unordered_set<tuple<P, int>> visited;

template <typename F>
int dfs(int y, int x, int count, const unordered_set<P> &s, F func,
        const unordered_set<P> &all) {
    // printf("%d: %d %d %d %lu\n", __LINE__, y, x, count, visited.size());
    int ret = 2;
    if (func(P(y, x))) {
        return count;
    }
    for (int dy = -1; dy <= 1; dy++) {
        for (int dx = -1; dx <= 1; dx++) {
            if (dy == 0 && dx == 0) continue;
            int ny = y + dy;
            int nx = x + dx;
            if (visited.count(make_tuple(P(ny, nx), count))) {
                continue;
            }
            if (ny < 0 || n <= ny) continue;
            if (nx < 0 || m <= nx) continue;
            if (all.count(P(ny, nx))) {
                visited.insert(make_tuple(P(ny, nx), count));
                // printf("\t%d: %d %d %d %d\n", __LINE__, ny, nx, count,
                //        visited.size());
                ret = min(ret, dfs(ny, nx, count, s, func, all));
            }
            if (count == 0) {
                // printf("\t%d: %d %d %d %d\n", __LINE__, ny, nx, count,
                // visited.size());
                ret = min(ret, dfs(ny, nx, count + 1, s, func, all));
            }
        }
    }

    return ret;
}

template <typename F>
int f(const unordered_set<P> &s, F func) {
    int ret = 2;
    visited.clear();
    for (auto &&e : s) {
        int a = dfs(e.first, e.second, 0, s, func, all);
        // printf("%d %d %d\n", e.first, e.second, a);
        ret = min(ret, a);
    }

    return ret;
}

int main() {
    cin >> n >> m >> k;
    rep(i, k) {
        int x, y;
        cin >> y >> x;
        all.insert(P(y, x));
        if (y == 0 || x == m - 1) s.insert(P(y, x));
        if (x == 0 || y == n - 1) t.insert(P(y, x));
    }
    int a = f(s, [](P p) { return p.second == 0 || p.first == n - 1; });
    a = min(a, f(t, [](P p) { return p.first == 0 || p.second == m - 1; }));
    cout << a << endl;
    return 0;
}

Compiler output:
a.cc:34:7: error: explicit specialization of 'template<class _Tp> struct std::hash' outside its namespace must use a nested-name-specifier [-fpermissive]
   34 | class hash<P> {
      |       ^~~~~~~
a.cc:45:7: error: explicit specialization of 'template<class _Tp> struct std::hash' outside its namespace must use a nested-name-specifier [-fpermissive]
   45 | class hash<tuple<P, int>> {
      |       ^~~~~~~~~~~~~~~~~~~