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: Accepted)

#include <bits/stdc++.h>

#define _overload(_1,_2,_3,name,...) name
#define _rep(i,n) _range(i,0,n)
#define _range(i,a,b) for(int i=int(a);i<int(b);++i)
#define rep(...) _overload(__VA_ARGS__,_range,_rep,)(__VA_ARGS__)

#define _rrep(i,n) _rrange(i,n,0)
#define _rrange(i,a,b) for(int i=int(a)-1;i>=int(b);--i)
#define rrep(...) _overload(__VA_ARGS__,_rrange,_rrep,)(__VA_ARGS__)

#define _all(arg) begin(arg),end(arg)
#define uniq(arg) sort(_all(arg)),(arg).erase(unique(_all(arg)),end(arg))
#define getidx(ary,key) lower_bound(_all(ary),key)-begin(ary)
#define clr(a,b) memset((a),(b),sizeof(a))
#define bit(x) __builtin_ctz(x)

template<class T>bool chmin(T &a, const T &b) { return (b<a)?(a=b,1):0;}
template<class T>bool chmax(T &a, const T &b) { return (a<b)?(a=b,1):0;}

using namespace std;
const int vmax=10010;
const int inf=1<<30;
struct edge{int to,cap,cost,rev;};
vector<edge> graph[vmax];

int h[vmax],dist[vmax];
int pv[vmax],pe[vmax];
typedef tuple<int,int> state;


void add_edge(int from,int to,int cap,int cost){
	graph[from].push_back({to,cap,cost,(int)graph[to].size()});
	graph[to].push_back({from,0,-cost,(int)graph[from].size()-1});
}

int min_cost_flow(int s,int t,int f,int n){
	int res=0;
	fill(h,h+n,0);
	while(f>0){
		priority_queue <state,vector<state>,greater<state> > q;
		fill(dist,dist+n,inf);
		dist[s]=0;
		q.push(state(0,s));
		while(!q.empty()){
			int cost,v;
			tie(cost,v)=q.top();q.pop();
			if(dist[v] < cost) continue;
			rep(i,graph[v].size()){
				edge &e=graph[v][i];
				if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
					dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
					pv[e.to]=v,pe[e.to]=i;
					q.push(state(dist[e.to],e.to));
				}
			}
		}
		if(dist[t]==inf) return -1;
		rep(v,n) h[v]+=dist[v];

		int d=f;
		for(int v=t;v!=s;v=pv[v]) d=min(d,graph[pv[v]][pe[v]].cap);
		f-=d;res+=d*h[t];
		for(int v=t;v!=s;v=pv[v]){
			edge &e=graph[pv[v]][pe[v]];
			e.cap-=d;
			graph[v][e.rev].cap+=d;
		}
	}
	return res;
}

int a[1010],b[1010];
vector<int> num;

int main(void){
	int n;
	cin >> n;
	rep(i,n) cin >> a[i] >> b[i];
	rep(i,n) num.push_back(a[i]),num.push_back(b[i]);
	uniq(num);

	int s=0,t=n+1+num.size()+1;
	rep(i,n){
		add_edge(s,i+1,1,0); 
		add_edge(i+1,n+1+num.size(),1,0); 
		add_edge(i+1,n+1+getidx(num,a[i]),1,-b[i]); 
		add_edge(i+1,n+1+getidx(num,b[i]),1,-a[i]); 
	}
	rep(i,num.size()) add_edge(n+1+i,t,1,0);
	add_edge(n+1+num.size(),t,inf,0);
	int m=t+1;
	cout << -min_cost_flow(s,t,n,m) << endl;
	return 0;
}