Problem:
D: Dangerous Tower

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，積み木を丁寧に積み上げることによって，決してミスタイピングをしないほどの手先の器用さを手に入れようというものである．せっかく積み木がたくさんあるので，高い塔を作ろう．

積み木は N 個あり，i 番目 (1 ≤ i ≤ N) の積み木は 1 × Ai × Bi の直方体の形をしている．長さ 1 の辺は奥行き方向に用いて，長さ Ai, Bi の辺を横方向と高さ方向に 1 つずつ割り当てることにした．積み木を積み上げるとき，上の段の積み木は下の段の積み木より横の長さが厳密に短くなければならない．積み木は好きな順番に使うことができ，また，使わない積み木があってもよい．このような制約下で，作ることが可能な最も高い塔を作りたい．

Input

N
A1 B1
...
AN BN

1 ≤ N ≤ 1,000，1 ≤ Ai，Bi ≤ 1,000,000 を満たす．入力の値はすべて整数である．

Output

塔の高さの最大値を 1 行に出力せよ．

Sample Input 1

3
10 40
10 40
20 30

Sample Output 1

80

Sample Input 2

4
1 2
2 3
3 4
4 1

Sample Output 2

11

Solution in C++11 (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,k,n) for(int i = (k); i < (n); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) a.begin(), a.end()
#define MS(m,v) memset(m,v,sizeof(m))
#define D10 fixed<<setprecision(10)
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
const int MOD = 1000000007;
const int INF = 10000000;
const ld EPS = 1e-12;
template<class T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<class T> T &chmax(T &a, const T &b) { return a = max(a, b); }

/*--------------------template--------------------*/

typedef int Weight;
typedef int Flow;
struct Edge {
	int src, dest, rev;
	Flow cap;
	Weight cost;
	bool operator < (const Edge &rhs) const
	{
		return cost > rhs.cost;
	}
	Edge(int s, int d) : src(s), dest(d) { ; }
	Edge(int s, int d, int c) : src(s), dest(d), cost(c) { ; }
	Edge(int s, int d, int r, Flow cp, Weight cst) : src(s), dest(d), rev(r), cap(cp), cost(cst) { ; }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;
void add_edge(Graph &g, int src, int dest, Flow cap)
{
	g[src].push_back(Edge{ src, dest, (int)g[dest].size(), cap, 0 });
	g[dest].push_back(Edge{ dest, src, (int)g[src].size() - 1, 0, 0 });
}

void add_edge(Graph &g, int from, int to, Flow cap, Weight cost)
{
	g[from].push_back(Edge(from, to, (int)g[to].size(), cap, cost));
	g[to].push_back(Edge(to, from, (int)g[from].size() - 1, 0, -cost));
}

Weight mincost_flow(Graph &g, int s, int t, Flow f)
{
	const int n = g.size();
	Weight res = 0;
	Array dist(n);
	vi prevv(n), preve(n);
	while (f > 0)
	{
		REP(i, n) dist[i] = (i == s) ? 0 : INF;
		bool update = true;
		while (update)
		{
			update = false;
			for (int v = 0; v < n; v++)
			{
				if (dist[v] == INF) continue;
				REP(i, g[v].size())
				{
					Edge& e = g[v][i];
					if (e.cap > 0 && dist[e.dest] > dist[v] + e.cost)
					{
						dist[e.dest] = dist[v] + e.cost;
						prevv[e.dest] = v;
						preve[e.dest] = i;
						update = true;
					}
				}
			}
		}
		if (dist[t] == INF) return -1; // cannot flow

		Flow 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;
	vector<pii> v;
	map<int, int> mp;
	REP(i, n)
	{
		int a, b; cin >> a >> b;
		if (!mp.count(a)) mp[a] = mp.size();
		if (!mp.count(b)) mp[b] = mp.size();
		v.emplace_back(a, b);
	}
	Graph g(n + mp.size() + 2);
	int V = g.size();
	REP(i, n)
	{
		add_edge(g, V - 2, i, 1, 0);
		add_edge(g, i, V - 1, 1, 0);
		add_edge(g, i, n + mp[v[i].first], 1, -v[i].second);
		add_edge(g, i, n + mp[v[i].second], 1, -v[i].first);
	}
	REP(i, mp.size()) add_edge(g, n + i, V - 1, 1, 0);
	cout << -mincost_flow(g, V - 2, V - 1, n) << endl;
	return 0;
}