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: Runtime Error)

#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(5 * N);
	pd.init();
	
	int s = 4 * N + 1, t = 4 * N + 2;
	
	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);
		pd.addEdge(i, vid[A[i]], 1, maxH - B[i]);
		pd.addEdge(i, vid[B[i]], 1, maxH - A[i]);
	}
	
	int ans = 101010, 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;
}