#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <utility>
#include <set>
#include <cctype>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
using namespace std;
#define INF 100000000

typedef long long ll;
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};

const int MAXV = 3072;
const int constNum = 2000000;

class minCostFlow {
public:
    minCostFlow(int N) : V(N) {}
    struct edge {
        int to;
        int cap;
        int cost;
        int rev;
    };
    int V;
    vector<edge> G[MAXV];
    int dist[MAXV];
    int prevv[MAXV];
    int preve[MAXV];

    void add_edge(int from, int to, int cap, int cost) {
        G[from].push_back((edge){to, cap, cost, (int)G[to].size()});
        G[to].push_back((edge){from, 0, -cost, (int)G[from].size()-1});
    }
    int min_cost_flow(int s, int t, int f) {
        int res = 0;
        while (f > 0) {
            for (int i = 0; i < MAXV; i++) dist[i] = 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 A[1024], B[1024];

int main(void) {
    int N;
    cin >> N;
    vector<int> vals;
    for (int i = 0; i < N; i++) {
        cin >> A[i] >> B[i];
        vals.push_back(A[i]);
        vals.push_back(B[i]);
    }
    sort(vals.begin(), vals.end());
    vals.erase(unique(vals.begin(), vals.end()), vals.end());
    minCostFlow mcf(MAXV);
    int s = 3040, t = s+1, dummy = t+1;
    for (int i = 0; i < N; i++) {
        mcf.add_edge(s, i, 1, 0);
        mcf.add_edge(i, dummy, 1, constNum);
    }
    for (int i = 0; i < vals.size(); i++) {
        mcf.add_edge(i+1024, t, 1, 0);
    }
    mcf.add_edge(dummy, t, INF, 0);
    for (int i = 0; i < N; i++) {
        int a = lower_bound(vals.begin(), vals.end(), A[i]) - vals.begin();
        int b = lower_bound(vals.begin(), vals.end(), B[i]) - vals.begin();
        mcf.add_edge(i, a+1024, 1, -B[i]+constNum);
        mcf.add_edge(i, b+1024, 1, -A[i]+constNum);
    }
    cout << -(mcf.min_cost_flow(s, t, N) - constNum * N) << endl;
    return 0;
}

Measured memory_bytes: 1596