TopCoder SRM 581 Div1 Medium TreeUnion

問題

N頂点からなる木A, Bがそれぞれ与えられる。
A, Bを次のようにしてつなぐ。
長さNの順列を等確率にランダムで一つ取り、これをP[i]とする。


Aのi番目の頂点とBのP[i]番目の頂点を辺で結ぶ。


こうしてできたグラフに、長さがちょうどkの単純閉路がいくつできるか、
その期待値を求めよ。

制約条件

N≦50
長さkの単純閉路とは、グラフ上にk個の異なる頂点v0, v1, ..., vk-1であって、
v0とv1, v1とv2, ..., vk-2とvk-1, vk-1とv0がそれぞれ辺で結ばれているようなもの。

方針

ソースコード

int n1, n2;
int d1[310][310], d2[310][310];
vector<vi> t1, t2;

vector<vi> parse(vector<string> s, int &n, int d[310][310]){
	
	string t;
	rep(i, s.size()) t += s[i];
	stringstream ss(t);
	
	int k;
	vi v;
	while(ss >> k) v.pb(k);
	
	n = v.size() + 1;
	vector<vi> e(n);
	
	rep(i, n) rep(j, n) d[i][j] = i == j ? 0 : inf;
	rep(i, v.size()){
		e[i + 1].pb(v[i]);
		e[v[i]].pb(i + 1);
		d[i + 1][v[i]] = d[v[i]][i + 1] = 1;
	}
	
	rep(k, n) rep(i, n) rep(j, n) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
	return e;
}

class TreeUnion {
	public:
	double expectedCycles(vector <string> tree1, vector <string> tree2, int K) {
		t1 = parse(tree1, n1, d1);
		t2 = parse(tree2, n2, d2);
		
		int cnt[310] = {};
		double ans = 0;
		
		rep(i, n2) rep(j, n2) if(i != j) cnt[d2[i][j]]++;
		
		rep(i, n1) rep(j, i){
			int r = K - d1[i][j] - 2;
			if(r <= 0 || r > 300) continue;
			
			ans += cnt[r] * 1.0 / n2 / (n2 - 1);
		}
		return ans;
	}
};