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++ (judge verdict: Wrong Answer)

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <functional>
#include <iostream>
#define INF 1000000007
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

typedef pair<int,int> P;
struct edge{
	int to,cap,cost,rev;
	edge(){}
	edge(int tt,int cc,int co,int re){
		to=tt;
		cap=cc;
		cost=co;
		rev=re;
	}
};

int V;
vector<edge> G[3005];
int h[3005];
int dist[3005];
int prevv[3005],preve[3005];

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

int min_cost_flow(int s,int t,int f){
	int res=0;
	fill(h,h+V,0);
	while(f>0){
		priority_queue<P,vector<P>,greater<P> > que;
		fill(dist,dist+V,INF);
		dist[s]=0;
		que.push(P(0,s));
		while(que.size()){
			P p=que.top();
			que.pop();
			int v=p.second;
			if(dist[v]<p.first)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+h[v]-h[e.to]){
					dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
					prevv[e.to]=v;
					preve[e.to]=i;
					que.push(P(dist[e.to],e.to));
				}
			}
		}
		if(dist[t]==INF)return -1;
		for(int v=0;v<V;v++){
			h[v]+=dist[v];
		}
		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*h[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 n;
int a[2001],b[2001];
vector<int> vec;

int main(void){
	scanf("%d",&n);
	int maxi=0;
	for(int i=0;i<n;i++){
		scanf("%d%d",&a[i],&b[i]);
		maxi=max(maxi,a[i]);
		maxi=max(maxi,b[i]);
		vec.push_back(a[i]);
		vec.push_back(b[i]);
	}
	sort(vec.begin(),vec.end());
	vec.erase(unique(vec.begin(),vec.end()),vec.end());
	int s=vec.size()+n,t=vec.size()+n+1;
	V=t+n+1;
	for(int i=0;i<n;i++){
		a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin();
		b[i]=lower_bound(vec.begin(),vec.end(),b[i])-vec.begin();
		add_edge(s,vec.size()+i,1,0);
		add_edge(vec.size()+i,a[i],1,maxi-vec[b[i]]);
		add_edge(vec.size()+i,b[i],1,maxi-vec[a[i]]);
	}
	for(int i=0;i<vec.size();i++){
		add_edge(i,t,1,0);
	}
	int res=0;
	int now=0;
	for(int i=0;i<n;i++){
		int v=min_cost_flow(s,t,1);
		if(v==-1)break;
		now+=maxi-v;
		res=max(res,now);
	}
	printf("%d\n",res);
	return 0;
}