Codeforces 387(#227 Div2 only) D. George and Interesting Graph

問題

有向グラフがinterestingであるとは、

  • 多重辺が存在しない。
  • 一つの頂点cがあり、cはほかのどの頂点へも辺があり、どの頂点からもcへの辺がある。
  • 頂点cには一本だけ自己辺がある。
  • c以外の頂点は入次数、出次数ともに2である

ことを言う。


多重辺の存在しない有向グラフが与えられる。
このグラフを辺の追加または削除をそれぞれ一回につきコスト1で行って、
interestingにするための最小コストを求めよ。

制約条件

頂点≦500
辺≦1000

方針

cを固定する。
cに自己辺がなかったらコスト1がかかる。
まずcからほかの頂点へ辺が出てなかったら頂点一つにつきコスト1がかかる
ほかの頂点からcへ辺が入ってなかったら頂点一つにつきコスト1がかかる。


で、cを含む辺に関するコストはこれで全てで、
cを含まない辺のコストを考える。


残りの頂点は、cを含む辺を捨てれば全て入次数、出次数が1である必要がある。
今残っている辺でできるだけこのような辺を取りたい。


これは二部グラフの最大マッチングでやればよくて、
左側に頂点iのoutに対応する頂点、右側に頂点iのinに対応する頂点をそれぞれ置いて、
元の辺(a, b)にたいしてaのoutからbのinへ辺を張ったグラフの最大マッチングを取ればいい。


残りの辺は使えないので捨てる。
で、n - 1本に足りない分の辺は生やさなければならないので生やす。
これを全ての頂点をcとして試せばいい。
計算量はO(n * マッチングの計算量)で、O(n^3 + n^2m)とか。

ソースコード

int n, m, g[500][500];
vector<vi> e;
vector<pi> es;

int p[1000];
bool use[1000];

bool rec(int s){
	if(s < 0) return 1;
	each(i, e[s]) if(!use[*i]){
		use[*i] = 1;
		if(rec(p[*i])) return p[*i] = s, p[s] = *i, 1;
	}
	return 0;
}

int matching(){
	int res = 0;
	rep(i, 2 * n) p[i] = -1;
	rep(i, 2 * n) if(p[i] < 0){
		rep(j, 2 * n) use[j] = 0;
		if(rec(i)) res++;
	}
	return res;
}

int main(){
	cin >> n >> m;
	
	rep(i, m){
		int a, b;
		cin >> a >> b;
		a--; b--;
		g[a][b] = 1;
		es.pb(mp(a, b));
	}
	
	int ans = inf;
	
	rep(i, n){
		int cost = !g[i][i];
		int cnt = 0;
		rep(j, n) if(i != j) cost += (!g[i][j]) + (!g[j][i]);
		
		e.clear();
		e.resize(2 * n);
		
		rep(j, m){
			if(es[j].first == i || es[j].second == i) continue;
			
			cnt++;
			e[es[j].first].pb(es[j].second + n);
			e[es[j].second + n].pb(es[j].first);
		}
		cost += n - 1 + cnt - 2 * matching();
		ans = min(ans, cost);
	}
	cout << ans << endl;
	
	return 0;
}