#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define R cin>>
#define ll long long
#define ln cout<<'\n'
#define in(a) insert(a)
#define pb(a) push_back(a)
#define pd(a) printf("%.10f\n",a)
#define mem(a) memset(a,0,sizeof(a))
#define all(c) (c).begin(),(c).end()
#define iter(c) __typeof((c).begin())
#define rrep(i,n) for(ll i=(ll)(n)-1;i>=0;i--)
#define REP(i,m,n) for(ll i=(ll)(m);i<(ll)(n);i++)
#define rep(i,n) REP(i,0,n)
#define tr(it,c) for(iter(c) it=(c).begin();it!=(c).end();it++)
ll check(ll n,ll m,ll x,ll y){return x>=0&&x<n&&y>=0&&y<m;}void pr(){ln;}
template<class A,class...B>void pr(const A &a,const B&...b){cout<<a<<(sizeof...(b)?" ":"");pr(b...);}
template<class A>void PR(A a,ll n){rep(i,n)cout<<(i?" ":"")<<a[i];ln;}
const ll MAX=1e9+7,MAXL=1LL<<61,dx[8]={-1,0,1,0,-1,-1,1,1},dy[8]={0,1,0,-1,-1,1,1,-1};
typedef pair<ll,ll> P;
clock_t t2;
#define MAX_V 600002
struct edge{ int to,cap,rev; };
vector<edge> G[MAX_V];
int level[MAX_V],iter[MAX_V];
  
void add_edge(int from,int to,int cap){
  G[from].push_back((edge){to,cap,G[to].size()});
  G[to].push_back((edge){from,0,G[from].size()-1});
}
 
void bfs(int s){
  memset(level,-1,sizeof(level));
  queue<int> Q;
  level[s] = 0;
  Q.push(s);
  while(!Q.empty()){
    int v = Q.front(); Q.pop();
    for(int i = 0 ; i < (int)G[v].size() ; i++){
      edge &e = G[v][i];
      if(e.cap > 0 && level[e.to] < 0){
        level[e.to] = level[v] + 1;
        Q.push(e.to);
      }
    }
  }
}
  
int dfs(int v,int t,int f){
  if(v == t) return f;
  for(int &i = iter[v] ; i < (int)G[v].size() ; i++){
    edge &e = G[v][i];
    if(e.cap > 0 && level[v] < level[e.to]){
      int d = dfs(e.to,t,min(f,e.cap));
      if(d > 0){
        e.cap -= d;
        G[e.to][e.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}
 
ll n;
int max_flow(int s,int t){
  int flow = 0;
  for(;;){
    clock_t t3=clock();
    double t4=(double)(t3-t2)/CLOCKS_PER_SEC;
    if((double)t3/CLOCKS_PER_SEC+t4*2>1.997) {
      pr(n);
      exit(0);
    }
    bfs(s);
    if(level[t] < 0) return flow;
    memset(iter,0,sizeof(iter));
    int f;
    while((f = dfs(s,t,MAX)) > 0){
      flow += f;
    }
  }
}

void Main() {
  t2=clock();
  R n;
  P a[n];
  rep(i,n) cin >> a[i].F >> a[i].S;
  rep(i,n) a[i].F--,a[i].S--;
  rep(i,n) {
    add_edge(600000,i,1);
    add_edge(i,n+a[i].F,1);
    if(a[i].F!=a[i].S) add_edge(i,n+a[i].S,1);
  }
  rep(i,400000) add_edge(n+i,600001,1);
  pr(max_flow(600000,600001));
}

int main(){ios::sync_with_stdio(0);cin.tie(0);Main();return 0;}

#line 1 "main.cpp"
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cfloat>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits.h>
#include <list>
#include <map>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <string.h>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define rep(i,n) for(int i=0;i<n;i++)
#define REP(i,n) for(int i=1;i<=n;i++)
#define int long long
#define ll long long
#define eps LDBL_EPSILON
#define mod (ll)1000000007
#define INF LLONG_MAX/10
#define P pair<int,int>
#define prique priority_queue
using namespace std;
int par[400010], rankh[400010], siz[400010], edge[400010];
void init(int n) {
	for (int i = 0; i <= n; i++) {
		par[i] = i;
		rankh[i] = 0;
		siz[i] = 1;
		edge[i] = 0;
	}
}
int find(int x) {
	if (par[x] == x)return x;
	else return par[x] = find(par[x]);
}
void unite(int x, int y) {
	x = find(x);
	y = find(y);
	if (x == y) {
		edge[x]++;
		return;
	}
	if (rankh[x] < rankh[y]) {
		par[x] = y;
		siz[y] += siz[x];
		edge[y] += edge[x] + 1;
	}
	else {
		par[y] = x;
		if (rankh[x] == rankh[y])rankh[x]++;
		siz[x] += siz[y];
		edge[x] += edge[y] + 1;
	}
}
bool same(int x, int y) {
	return find(x) == find(y);
}
int size(int x) {
	return siz[find(x)];
}
int edges(int x) {
	return edge[find(x)];
}
int n, a[200010], b[200010];
map<int, int> mp;
signed main() {
	cin >> n;
	rep(i, n) {
		cin >> a[i] >> b[i];
		mp[a[i]] = 0;
		mp[b[i]] = 0;
	}
	int cnt = 1;
	for (pair<const int, int>& p : mp) {
		p.second = cnt;
		cnt++;
	}
	init(mp.size());
	rep(i, n) {
		unite(mp[a[i]], mp[b[i]]);
	}
	set<int> st;
	int ans = 0;
	REP(i, mp.size()) {
		if (st.find(find(i)) != st.end())continue;
		ans += min(edges(i), size(i));
		st.insert(find(i));
	}
	cout << ans << endl;
}
