#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
using P=pair<ll,ll>;
#define MOD 1000000007ll
//#define INF 1000000000ll
#define EPS 1e-10
#define FOR(i,n,m) for(ll i=n;i<(ll)m;i++)
#define REP(i,n) FOR(i,0,n)
#define DUMP(a) REP(d,a.size()){cout<<a[d];if(d!=a.size()-1)cout<<" ";else cout<<endl;}
#define ALL(v) v.begin(),v.end()
#define UNIQUE(v) sort(ALL(v));v.erase(unique(ALL(v)),v.end());
#define pb push_back

using Flow = ll;
using Cost = ll;
const ll MAX_V = 5000;
const Cost INF = std::numeric_limits<Cost>::max() / 8;

struct PrimalDual {
	struct Edge {
		ll d;
		Flow c, f;
		Cost w;
		ll r, is_r;
		Edge(ll d_, Flow c_, Flow f_, Cost w_, ll r_, bool is_r_)
		: d(d_), c(c_), f(f_), w(w_), r(r_), is_r(is_r_) {}
	};

	ll n;
	std::vector<std::vector<Edge> > g;
	PrimalDual(ll n_) : n(n_), g(std::vector<std::vector<Edge> >(n_)) {}

	void add_edge(ll src, ll dst, Flow cap, Cost cost) {  // 有向辺
		ll rsrc = g[dst].size();
		ll rdst = g[src].size();
		g[src].emplace_back(dst, cap, 0, cost, rsrc, false);
		g[dst].emplace_back(src, cap, cap, -cost, rdst, true);
	}

	Cost solve(ll s, ll t, Flow f) {
		vector<vector<Edge>> ng=g;
		Cost res = 0;
		static Cost h[MAX_V + 10], dist[MAX_V];
		static int prevv[MAX_V + 10], preve[MAX_V + 10];
		// std::vector<Cost> h(g.size()), dist(g.size());
		// std::vector<int> prevv(g.size()), preve(g.size());

		using pcv = std::pair<Cost, ll>;
		std::priority_queue<pcv, std::vector<pcv>, std::greater<pcv> > q;
		std::fill(h, h + n, 0);
		while (f > 0) {
			std::fill(dist, dist + n, INF);
			dist[s] = 0;
			q.emplace(0, s);
			while (q.size()) {
				Cost cd;
				ll v;
				std::tie(cd, v) = q.top();
				q.pop();
				if (dist[v] < cd) continue;
				for (ll i = 0; i < (ll)(ng[v].size()); ++i) {
					Edge &e = ng[v][i];
					if (residue(e) == 0) continue;
					if (dist[e.d] + h[e.d] > cd + h[v] + e.w) {
						dist[e.d] = dist[v] + e.w + h[v] - h[e.d];
						prevv[e.d] = v;
						preve[e.d] = i;
						q.emplace(dist[e.d], e.d);
					}
				}
			}

			if (dist[t] == INF) return INF;  // 経路が見つからなかった

			// s-t 間最短路に沿って目一杯流す
			for (ll i = 0; i < n; ++i) h[i] += dist[i];
			Flow d = f;
			for (ll v = t; v != s; v = prevv[v]) {
				d = std::min(d, residue(ng[prevv[v]][preve[v]]));
			}
			f -= d;
			res += d * h[t];
			for (ll v = t; v != s; v = prevv[v]) {
				Edge &e = ng[prevv[v]][preve[v]];
				e.f += d;
				ng[v][e.r].f -= d;
			}
		}
		return res;
	}

	Flow residue(const Edge &e) { return e.c - e.f; }

	void show() {
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < (int)(g[i].size()); ++j) {
				Edge &e = g[i][j];
				if (e.is_r) continue;
				printf("%3d->%3d (flow:%d)\n", i, (int)e.d, (int)e.f);
			}
		}
	}
};

ll n;

ll solve() {
	vector<ll> a(n);
	vector<ll> b(n);
	REP(i,n) cin>>a[i]>>b[i];
	vector<ll> num;
	REP(i,n) num.pb(a[i]);
	REP(i,n) num.pb(b[i]);
	UNIQUE(num);
	PrimalDual pd(n+(ll)num.size()+3);
	REP(i,n) pd.add_edge(0,1+i,1,0);
	REP(i,(ll)num.size()) pd.add_edge(1+n+i,n+(ll)num.size()+1,1,0);
    pd.add_edge(n+(ll)num.size()+2,n+(ll)num.size()+1,INF,0);
	REP(i,n) {
		ll idxa=(lower_bound(ALL(num),a[i])-num.begin());
		ll idxb=(lower_bound(ALL(num),b[i])-num.begin());
		pd.add_edge(1+i,1+n+idxa,1,-b[i]);
		pd.add_edge(1+i,1+n+idxb,1,-a[i]);
        pd.add_edge(1+i,n+(ll)num.size()+2,1,0);
	}
    return -pd.solve(0,n+(ll)num.size()+1,n);
}

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	cin>>n;
	cout<<solve()<<endl;
	return 0;
}




Measured memory_bytes: 4372