#include <stdio.h>
#include <math.h>
#include <bitset>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <iostream>

#define VARIABLE(x) cerr << #x << "=" << x << endl
#define BINARY(x) cerr << #x << "=" << static_cast<bitset<16> >(x) << endl;
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define REP(i,m,n) for (int i=m;i<(int)(n);i++)
#define if_range(x, y, w, h) if (0<=(int)(x) && (int)(x)<(int)(w) && 0<=(int)(y) && (int)(y)<(int)(h))

const int INF = 100000000;
typedef double D;
const double EPS = 1e-8;
const double PI = 3.14159;
int dx[4]={-1, 0, 1, 0}, dy[4]={0, -1, 0, 1};
using namespace std;
typedef pair<int, int> P;

/** Problem2293 : Dangerous Tower **/
const int MAX_V = 3010;

class Flow {
public:
	struct edge { int to, cap, rev, cost;};
	vector<edge> G[MAX_V];
	bool used[MAX_V];
	int V;
	
	int dist[MAX_V];
	int prevv[MAX_V], preve[MAX_V];
	
	Flow() {V=MAX_V;}
	Flow(int v) {
		V = v;
	}
	
	void add_edge(int from, int to, int cap) {
		G[from].push_back((edge){to, cap, (int)G[to].size(), 0});
		G[to].push_back((edge){from, 0, (int)G[from].size()-1, 0});
	}
	
	void add_edge_with_cost(int from, int to, int cap, int cost) {
		G[from].push_back((edge){to, cap, (int)G[to].size(), cost});
		G[to].push_back((edge){from, 0, (int)G[from].size()-1, -cost});
	}
	
	// 最大流
	int dfs(int v, int t, int f) {
		if (v==t) return f;
		used[v] = true;
		for (int i=0; i<G[v].size(); i++) {
			edge &e = G[v][i];
			if (!used[e.to] && e.cap>0) {
				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;
	}
	
	int max_flow(int s, int t) {
		int flow = 0;
		for (;;) {
			memset(used, 0, sizeof(used));
			int f = dfs(s, t, INF);
			if (f==0) return flow;
			flow += f;
		}
	}
	
	// 最小費用流
	int min_cost_flow(int s, int t, int f) {
		int res=0;
		while (f>0) {
			fill(dist, dist+V, INF);
			dist[s]=0;
			bool update=true;
			while (update) {
				update = false;
				for (int v=0; v<V; v++) {
					if (dist[v]==INF) continue;
					for (int i=0; i<G[v].size(); i++) {
						edge &e = G[v][i];
						if (e.cap>0 && dist[e.to] > dist[v] + e.cost) {
							dist[e.to] = dist[v] + e.cost;
							prevv[e.to] = v;
							preve[e.to] = i;
							update = true;
						}
					}
				}
			}
			
			if (dist[t] == INF) {
				return -1;
			}

			int d=f;
			for (int v=t; v!=s; v=prevv[v]) {
				d = min(d, G[prevv[v]][preve[v]].cap);
			}
			f -= d;
			res += d*dist[t];
			for (int v=t; v!=s; v=prevv[v]) {
				edge &e = G[prevv[v]][preve[v]];
				e.cap -= d;
				G[v][e.rev].cap += d;
			}
		}
		return res;
	}
};


int main()
{
	int N; cin>>N;
	//while (cin>>N) {
		Flow F;
		map<int, int> tmp; int idx=0;
		
		rep(i, N) {
			int a, b; cin>>a>>b;

			if (tmp.count(a)==0) {
				F.add_edge_with_cost(i, N+idx, 1, -b);
				tmp[a]=idx++;
			} else {
				F.add_edge_with_cost(i, N+tmp[a], 1, -b);
			}
			
			
			if (tmp.count(b)==0) {
				F.add_edge_with_cost(i, N+idx, 1, -a);
				tmp[b] = idx++;
			} else {
				F.add_edge_with_cost(i, N+tmp[b], 1, -a);
			}
		}
		
		int M = (int)tmp.size();
		int s = N+M, t=s+1, d=t+1;
		rep(i, N) {
			F.add_edge_with_cost(s, i, 1, 0);
			F.add_edge_with_cost(i, d, 1, 0);
		}
		rep(i, M) {
			F.add_edge_with_cost(N+i, t, 1, 0);
		}
		F.add_edge_with_cost(d, t, INF, 0);
		F.V = M+N+3;
		
		int ans = F.min_cost_flow(s, t, N);
		cout << -ans << endl;
	//}
}

Measured memory_bytes: 1704