Problem:
Problem F: Great Devil Sakanikia

Problem

大悪魔サカーニャは今日も天敵の猫に襲われていた。

いつもやられている訳にはいかないので、秘密兵器を購入した。

この秘密兵器は、巨大な岩を生成することで猫の移動経路を塞ぎ、猫がこちらに近づけないようにすることができる。

今、サカーニャと一匹の猫がマス(0,0),(n−1,0),(n−1,m−1),(0,m−1)で囲まれた長方形の閉区間内にいる。

マス(0,0)に猫、マス(n−1,m−1)にサカーニャがいる。

猫は上下左右の隣接したマスに移動することができるが、区間外に出ることはできない。

いくつかのマスは、穴や障害物の影響で侵入することができない。

サカーニャは、あるマスに1つ岩を生成することでそのマスに猫が侵入できなくすることができる。

ただし、マス(0,0)とマス(n−1,m−1)に岩を生成することはできない。

マス(0,0)からマス(n−1,m−1)までの移動経路を塞ぐために必要な、生成する岩の数の最小値を求めよ。

Input

n m k
x1 y1
...
xk yk

入力はすべて整数で与えられる。

1行目にマスの大きさを表す２つの整数nとm、侵入できないマスの数kが空白区切りで与えられる。

2行目からk行に侵入できないマスの座標が与えられる。

Constraints

入力は以下の条件を満たす。

2 ≤ n,m ≤ 105

0 ≤ k ≤ min(n×m−2,105)

0 ≤ xi ≤ n − 1

0 ≤ yi ≤ m − 1

(xi,yi) ≠ (xj,yj) (i ≠ j)

(xi,yi) ≠ (0,0) ≠ (n−1,m−1)

Output

マス(0,0)からマス(n−1,m−1)までの移動経路を塞ぐために必要な、生成する岩の数の最小値を1行に出力せよ。

Sample Input 1

3 5 2
0 2
2 2

Sample Output 1

1

Sample Input 2

5 5 3
0 2
2 2
4 1

Sample Output 2

2

Solution in C++14 (judge verdict: Memory Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;
/*{{{*/  //template
#define REP(i,n) for(int i=0;i<n;i++)
#define rep(i,n) for(int i=0;i<n;i++)
#define INF 1<<29
#define LINF LLONG_MAX/3
#define MP make_pair
#define PB push_back
#define pb push_back
#define EB emplace_back
#define ALL(v) (v).begin(),(v).end()
#define all(v) ALL(v)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define debug2(x,y) cerr<<#x<<","<<#y":"<<x<<","<<y<<endl
#define CININIT cin.tie(0),ios::sync_with_stdio(false)
//struct fin{ fin(){ cin.tie(0); ios::sync_with_stdio(false); } } fin_;
struct Double{ double d; explicit Double(double x) : d(x){} };
ostream& operator<<(ostream& os,const Double x){ os << fixed << setprecision(20) << x.d; return os; }
template<typename T> ostream& operator<<(ostream& os,const vector<T>& vec){ os << "["; for(const auto& v : vec){ os << v << ","; } os << "]"; return os; }
template<typename T,typename U> ostream& operator<<(ostream& os,const pair<T,U>& p){ os << "(" << p.first << ","<< p.second <<")"; return os; }
template<typename T> ostream& operator<<(ostream& os,const set<T> &st){ os << "["; for(auto a : st) cout << a << ","; os << "]"; }
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
ll gcd(ll a,ll b){ if(b==0) return a; else return gcd(b,a%b); }
 
constexpr ll mod = 1e9+7;
constexpr int dx[]={0,-1,-2,-2,-2,-2,-2,-1,0,1,2,2,2,2,2,1};
constexpr int dy[]={2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1,0,1,2,2};
/*}}}*/

constexpr int MAX_K = 100010;

int N,M,K;
int X[MAX_K],Y[MAX_K];
//bool used[MAX_K];
map<int,map<int,int>> tbl;
map<int,map<int,bool>> vis;
set<pii> ex;

// black: ??????????????????
// white: ???????????????


int main(){
    cin >> N >> M >> K;
    rep(i,K){
        cin >> X[i] >> Y[i];
        tbl[X[i]][Y[i]] = 0;
        vis[X[i]][Y[i]] = false;
        ex.insert(pii(X[i],Y[i]));
    }

    queue<pii> que;
    for(int i=0;i<K;i++){
        if(vis[X[i]][Y[i]]) continue;
        int x=X[i],y=Y[i];
        if(x==0 or y==M-1){
            //debug2(x,y);
            que.push(pii(x,y));
        }
    }


    //cerr << "check1" << endl;
    while(!que.empty()){
        auto p = que.front();
        que.pop();
        int x = p.first;
        int y = p.second;
        tbl[x][y] |= 1;
        vis[x][y] = true;
        for(int dx=-1;dx<=1;dx++) for(int dy=-1;dy<=1;dy++) if(dx!=0 or dy!=0){
            int nx = x + dx;
            int ny = y + dy;
            if(nx<0 or nx>=N or ny<0 or ny>=M) continue;
            if(ex.count(pii(nx,ny)) and !vis[nx][ny]){ // black is  exist around (x,y)
                if(nx==0 and ny==0) continue;
                //cerr << "\t" << nx << " " << ny << endl;
                que.push(pii(nx,ny));
            }
        }
    }



    //cerr << "check2" << endl;
    for(int i=0;i<K;i++){
        vis[X[i]][Y[i]] = false;
    }


    for(int i=0;i<K;i++){
        if(vis[X[i]][Y[i]]) continue;
        int x = X[i],y=Y[i];
        if(y==0 or x==N-1){
            que.push(pii(x,y));
        }
    }

    while(!que.empty()){
        auto p = que.front();
        que.pop();
        int x = p.first;
        int y = p.second;
        //debug2(x,y); 
        tbl[x][y] |= 2;
        vis[x][y] = true;
        for(int dx=-1;dx<=1;dx++) for(int dy=-1;dy<=1;dy++) if(dx!=0 or dy!=0){
            int nx = x + dx;
            int ny = y + dy;
            //debug2(nx,ny);
            if(nx<0 or nx>=N or ny<0 or ny>=M) continue;
            //cerr << "\t" << nx << " " << ny << " " << ex.count(pii(nx,ny)) << " " << vis[nx][ny] << endl;
            //cerr << "\t(" << nx << "," << ny << ") -> " << ex.count(pii(nx,ny)) << " " <<  vis[nx][ny] << endl;
            if(ex.count(pii(nx,ny)) and !vis[nx][ny]){ // black is  exist around (x,y)
                que.push(pii(nx,ny));
            }
        }
    }

    // debug
    //for(int i=0;i<N;i++){
    //    for(int j=0;j<M;j++){
    //        cerr << tbl[i][j] << " ";
    //    }
    //    cerr << endl;
    //}

    for(int i=0;i<K;i++){
        if(tbl[X[i]][Y[i]] == 3){
            cout << 0 << endl;
            return 0;
        }
    }

    for(int i=0;i<K;i++){
        int x = X[i];
        int y = Y[i];
        if(tbl[x][y]==1){
            for(int j=0;j<16;j++){
                int nx = x + dx[j];
                int ny = y + dy[j];
                if(nx>=N or ny<0){
                    cout << 1 << endl;
                    return 0;
                }
                if(nx<0 or nx>=N or ny<0 or ny>=M) continue;
                if(tbl[nx][ny]==2){
                    cout << 1 << endl;
                    return 0;
                }
            }
        }else if(tbl[x][y]==2){
            for(int j=0;j<16;j++){
                int nx = x + dx[j];
                int ny = y + dy[j];
                if(nx<0 or ny>=M){
                    cout << 1 << endl;
                    return 0;
                }
                if(nx<0 or nx>=N or ny<0 or ny>=M) continue;
                if(tbl[nx][ny]==1){
                    cout << 1 << endl;
                    return 0;
                }
            }
        }
    }

    cout << 2 << endl;
    return 0;
}