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

#define for_(i,a,b) for(int i=(a);i<(b);++i)
#define allof(a) (a).begin(),(a).end()
#define size_of(a) (int)(a).size()

const int iINF = 1L << 30;

template< typename FLOW, typename COST >
class PrimalDual {
private:
	typedef pair< COST, int > pci;
	static const COST cINF = COST(iINF);
	
	struct Edge {
		int to, rev; FLOW cap; COST cost;
		Edge(int to_, int rev_, FLOW cap_, COST cost_)
		: to(to_), rev(rev_), cap(cap_), cost(cost_) {}
	};
	
	int V;
	vector< vector< Edge > > edges;
	vector< COST > pot, cost;
	vector< int > prevv, preve;
	
public:
	PrimalDual(int n) : V(n), edges(n), pot(n, COST()),
						cost(n, COST()), prevv(n, -1), preve(n, -1) {}
	
	void addEdge(int from, int to, FLOW cap, COST cost) {
		edges[from].push_back(Edge(to, size_of(edges[to]), cap, cost));
		edges[to].push_back(Edge(from, size_of(edges[from]) - 1, FLOW(), -cost));
	}
	
	void init() { fill(allof(pot), 0); }
	
	void minCostFlow(int s, int t, FLOW f, COST& res) {		
		while (f > 0) {
			/** bellman ford ver **/
			/*
			fill(allof(cost), cINF);
			cost[s] = COST();
			bool update = 1;
			
			while (update) {
				update = 0;
				
				for_(v,0,V) {
					if (cost[v] == cINF) continue;
					
					int edge_nums = size_of(edges[v]);
					for_(i,0,edge_nums) {
						Edge& e = edges[v][i];
						
						if (e.cap > 0 && cost[e.to] > cost[v] + e.cost) {
							cost[e.to] = cost[v] + e.cost;
							prevv[e.to] = v;
							preve[e.to] = i;
							update = 1;
						}
					}
				}
			}
			*/
			/** --- **/
			
			/** dijkstra ver **/
			priority_queue< pci, vector< pci >, greater< pci > > que;
			fill(allof(cost), cINF);
			cost[s] = COST();
			que.push(pci(COST(), s));
			
			while (!que.empty()) {
				pci p = que.top(); que.pop();
				int v = p.second;
				
				if (cost[v] < p.first) continue;
				
				int edge_nums = size_of(edges[v]);
				for_(i,0,edge_nums) {
					Edge& e = edges[v][i];
					if (e.cap > 0 && cost[e.to] > cost[v] + e.cost + pot[v] - pot[e.to]) {
						cost[e.to] = cost[v] + e.cost + pot[v] - pot[e.to];
						prevv[e.to] = v;
						preve[e.to] = i;
						que.push(pci(cost[e.to], e.to));
					}
				}
			}
			/** --- **/
			
			if (cost[t] == cINF) {
				res = -1;
				return;
			}
			
			for_(i,0,V) pot[i] += cost[i];
			
			FLOW d = f;
			for (int u = t; u != s; u = prevv[u]) d = min(d, edges[prevv[u]][preve[u]].cap);
			f -= d;			
			res += (COST)d * pot[t];
			
			/** bellman ford ver **/
			//res += d * cost[t];
			/** --- **/
			
			for (int u = t; u != s; u = prevv[u]) {
				Edge& e = edges[prevv[u]][preve[u]];
				e.cap -= d;
				edges[u][e.rev].cap += d;
			}
		}
	}
};

int main() {
	int N;
	cin >> N;
	
	vector< int > A(N), B(N);
	int maxH = 0;
	
	for_(i,0,N) {
		cin >> A[i] >> B[i];
		maxH = max(maxH, A[i]);
		maxH = max(maxH, B[i]);
	}
	
	int id = N;
	map< int, int > vid;

	PrimalDual< int, int > pd(3 * N + 2);
	
	int s = 3 * N, t = 3 * N + 1;
	
	for_(i,0,N) {
		if (vid.count(A[i]) == 0) {
			vid[A[i]] = id;
			pd.addEdge(id, t, 1, 0);
			++id;
		}
		
		if (vid.count(B[i]) == 0) {
			vid[B[i]] = id;
			pd.addEdge(id, t, 1, 0);
			++id;
		}
	}

	for_(i,0,N) {
		pd.addEdge(s, i, 1, 0);
		//cerr << vid[A[i]] << " " << vid[B[i]] << endl;
		pd.addEdge(i, vid[A[i]], 1, maxH - B[i]);
		pd.addEdge(i, vid[B[i]], 1, maxH - A[i]);
	}
	
	pd.init();
	int ans = 1e9 + 7, res = 0;

	for_(f,0,N) {
		pd.minCostFlow(s, t, 1, res);
		if (res == -1) break;
		ans = min(res - (f + 1) * maxH, ans);
	}
	
	cout << (-ans) << endl;
	
	return 0;
}

Measured memory_bytes: 3504