#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
const ld eps = 1e-9;
const ll MOD = 1000000007;
const int INF = 1000000000;
const ll LINF = 1ll<<50;
template<typename T>
void printv(const vector<T>& s) {
  for(int i=0;i<(int)(s.size());++i) {
    cout << s[i];
    if(i == (int)(s.size())-1) cout << endl;
    else cout << " ";
  }
}
template<typename T1, typename T2>
ostream& operator<<(ostream &os, const pair<T1, T2> p) {
  os << p.first << ":" << p.second;
  return os;
}
template<typename T>
struct edge {
    int src, to;
    T cost;
};
template<typename T>
using Graph = vector<vector<edge<T>>>;
template<typename flow_t, typename cost_t>
struct PrimalDual {
    const cost_t INF;
    struct edge {
        int to;
        flow_t cap;
        cost_t cost;
        int rev;
    };
    vector<vector<edge>> g;
    vector<cost_t> h, d;
    vector<int> prevv, preve;
    PrimalDual(int V) : g(V), INF(numeric_limits< cost_t >::max()) {}
    void add_edge(int from, int to, flow_t cap, cost_t cost) {
        g[from].push_back({to, cap, cost, (int)g[to].size()});
        g[to].push_back({from, 0, -cost, (int)g[from].size()-1});
    }
    cost_t min_cost_flow(int s, int t, flow_t f) {
        int V = (int)g.size();
        cost_t ret = 0;
        using Pi = pair<cost_t, int>;
        priority_queue<Pi, vector<Pi>, greater<Pi>> que;
        h.assign(V, 0);
        preve.assign(V, -1);
        prevv.assign(V, -1);
        while (f > 0) {
            d.assign(V, INF);
            que.emplace(0, s);
            d[s] = 0;
            while (!que.empty()) {
                Pi p = que.top(); que.pop();
                if (d[p.second] < p.first) continue;
                for (int i = 0; i < g[p.second].size(); i++) {
                    edge &e = g[p.second][i];
                    cost_t nextCost = d[p.second] + e.cost +
                        h[p.second] - h[e.to];
                    if (e.cap > 0 && d[e.to] > nextCost) {
                        d[e.to] = nextCost;
                        prevv[e.to] = p.second, preve[e.to] = i;
                        que.emplace(d[e.to], e.to);
                    }
                }
            }
            if (d[t] == INF) return -1;
            for (int v = 0; v < V; v++) h[v] += d[v];
            flow_t addflow = f;
            for (int v = t; v != s; v = prevv[v]) {
                addflow = min(addflow, g[prevv[v]][preve[v]].cap);
            }
            f -= addflow;
            ret += addflow * h[t];
            for (int v = t; v != s; v = prevv[v]) {
                edge &e = g[prevv[v]][preve[v]];
                e.cap -= addflow;
                g[v][e.rev].cap += addflow;
            }
        }
        return ret;
    }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  int n; cin >> n;
  vector<P> v(n);
  set<int> st;
  for(int i=0;i<n;++i) {
    cin >> v[i].first >> v[i].second;
    st.insert(v[i].first);
    st.insert(v[i].second);
  }
  map<int, int> zatu;
  int id = 0;
  for(auto &e: st) {
    zatu[e] = id;
    id++;
  }
  PrimalDual<ll, ll> flow(2 + id + n);
  for(int i=0;i<n;++i) {
    flow.add_edge(1 + zatu[v[i].first], 1 + id + i, 1, -v[i].second);
    flow.add_edge(1 + zatu[v[i].second], 1 + id + i, 1, -v[i].first);
    flow.add_edge(1 + id + i, 1 + id + n, 1, 0);
  }
  for(int i=0;i<id;++i) {
    flow.add_edge(0, 1 + i, 1, 0);
  }
  flow.add_edge(0, 1 + id + n, INF, 0);
  ll mi = 0;
  cout << -flow.min_cost_flow(0, 1+id+n, INF) << endl;
}



Measured memory_bytes: 3900