#include <bits/stdc++.h>
using namespace std;

#define rep(i,x,y) for(int i=(x);i<(y);++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define dump(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define dump(x)
#endif

typedef long long int ll;
typedef pair<int,int> pii;
//template<typename T> using vec=std::vector<T>;

const int inf=1<<30;
const long long int infll=1LL<<58;
const double eps=1e-9;
const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec){
    os << "[";
    for (const auto &v : vec) {
    	os << v << ",";
    }
    os << "]";
    return os;
}

class union_find{
	private:
	vector<int> parent,rank;
	int size;
	public:
    int cnt;

    union_find()=default;
    union_find(int n){ init(n); }

    void init(int n){
		size=n;
		cnt=n;
		parent.resize(size);
		rank.resize(size);
		for(int i=0; i<size; ++i){
			parent[i]=i;
			rank[i]=0;
		}
	}

	int find(int x){
		if(parent[x]==x) return x;
		else return parent[x]=find(parent[x]);
	}

	void unite(int x,int y){
		x=find(x);
		y=find(y);
		if(x==y) return;
		if(rank[x]<rank[y]){
			parent[x]=y;
		} else {
			parent[y]=x;
			if(rank[x]==rank[y]) ++rank[x];
		}
		--cnt;
	}

	bool is_same(int x,int y){
		return find(x)==find(y);
	}
};

void solve(){
    int n,w,h;
    cin >> n >> w >> h;

    union_find uf(n);
    vector<array<bool,4>> flags;
    map<int,vector<pii>> mp1,mp2;
    rep(i,0,n){
        int x,y;
        cin >> x >> y;
        --x;
        --y;
        mp1[x].emplace_back(make_pair(y,i));
        mp2[y].emplace_back(make_pair(x,i));
        flags.emplace_back(array<bool,4>{x==0,y==0,x==w-1,y==h-1});
    }

    auto update=[](array<bool,4> &a,array<bool,4> &b){
        rep(i,0,4) a[i]|=b[i];
    };
    int cnt_move=0;
    for(auto it=mp1.begin(); it!=mp1.end(); ++it) for(const auto &p:it->second){
        if(uf.is_same(it->second.front().second,p.second)) continue;
        const int x=uf.find(it->second.front().second),y=uf.find(p.second);
        uf.unite(x,y);
        update(flags[uf.find(p.second)],flags[x]);
        update(flags[uf.find(p.second)],flags[y]);
        ++cnt_move;
    }
    for(auto it=mp2.begin(); it!=mp2.end(); ++it) for(const auto &p:it->second){
        if(uf.is_same(it->second.front().second,p.second)) continue;
        const int x=uf.find(it->second.front().second),y=uf.find(p.second);
        uf.unite(x,y);
        update(flags[uf.find(p.second)],flags[x]);
        update(flags[uf.find(p.second)],flags[y]);
        ++cnt_move;
    }

    if(uf.cnt==1){
        cout << cnt_move << endl;
        return;
    }

    int ans=inf;
    set<int> reps;
    rep(i,0,n) reps.insert(uf.find(i));
    rep(i,0,4){
        int cnt=0;
        for(int idx:reps) if(!flags[idx][i]) ++cnt;
        ans=min(ans,cnt_move+cnt);
    }
    ans+=uf.cnt-1;
    cout << ans << endl;
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    cout << fixed << setprecision(8);
    solve();
    return 0;
}