TopCoder SRM 371 SRM Div1 Medium ChessMatchup

問題

n人のチェスのチームが二つある。
自軍のそれぞれの人の強さはus[i]で表され、敵軍のそれぞれの人の強さはthem[i]で表される。


それぞれのチームからn人を順番に出し、勝負(強さの大きい人が必ず勝つ。強さが同じなら引き分け)をして、
勝ったら2点、引き分けなら1点がもらえる。


相手のn人を出してくる順番がわかっているとき、
自軍は最大で何点を得られるか、求めよ。

制約条件

n≦50

方針

自軍のi番目の人と敵軍のj番目の人が戦ったときに自軍に得られる得点をs[i][j]としたとき、
自軍のi番目の人に相当する頂点から敵軍のj番目の人に相当する頂点に、
コスト-s[i][j], 容量1の辺を張ると、
得られる最大のスコアはこのグラフの最小費用流になっている。


なので、最小費用流問題を解けばよい。

ソースコード

費用流は蟻本実装。

const int MAX_V=102;
struct edge{ int to,cap,cost,rev; };
int V;
vector<edge> G[MAX_V];
int dist[MAX_V], prevv[MAX_V], preve[MAX_V];

void add_edge(int from,int to,int cap,int cost){
	G[from].pb((edge){to, cap, cost, G[to].size()});
	G[to].pb((edge){from, 0, -cost, G[from].size()-1});
}
int min_cost_flow(int s,int t,int f){
	int res=0;
	while(f>0){
		fill(dist,dist+V,inf);
		dist[s]=0;
		bool update=1;
		while(update){
			update=0;
			rep(v,V){
				if(dist[v]==INF)continue;
				rep(i,G[v].size()){
					edge &e=G[v][i];
					if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
						dist[e.to]=dist[v]+e.cost;
						prevv[e.to]=v;
						preve[e.to]=i;
						update=1;
					}
				}
			}
		}
		if(dist[t]==inf)return -1;
		
		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*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;
}

class ChessMatchup {
	public:
	int maximumScore(vector <int> us, vector <int> them) 
	{
		int n=us.size();
		V=n*2+2;
		rep(i,V)G[i].clear();
		rep(i,n)rep(j,n)
			add_edge(i,j+n,1,us[i]==them[j]?1:us[i]<them[j]?2:0);
		rep(i,n)add_edge(V-2,i,1,0), add_edge(i+n,V-1,1,0);
		return n*2-min_cost_flow(V-2,V-1,n);
	}
};