kmjp's blog

競技プログラミング参加記です

TopCoder SRM 581 Div2 hard TreeUnionDiv2

さてDiv2 Hard。これはDiv1 Mediumを簡単にした問題。
幸いさくっと解法が思いついた。
http://community.topcoder.com/stat?c=problem_statement&pm=12587

問題

最大N点(<=9)からなる同じ点数の木が2つ与えられる。
2つの木の各点をそれぞれ辺でつないで、1つのグラフを作ったとする。
その時、長さKの閉路が最大数できるグラフについて、その閉路の最大数を答える。

解法

K<=7なのがポイント。
2つの木をA,Bとして、Aのある点から閉路を辿ろうとした場合、1度A-B間の辺を伝ってBに渡り、また別のA-B間の辺を伝ってAに戻らなければならない。
K<=7なので、この行き来は1往復しかない。

AとBの辺の張り方をnext_permutationでN!通り作成する。
そして、Aから2点Ai,Ajを選んだとき、それぞれからつながるBの2点をBk,Blとして、dist(Ai,Aj)+dist(Bk,Bl)+2==Kなら長さKの閉路が1本できる。

計算量はO(N!*N^2)でNの指数関数になるが、N<=9なので十分間に合う。
再帰にFloyd法で点の間の距離を計算しておくとラク。

class TreeUnionDiv2 {
	int T,K;
	int dist[2][10][10];
	vector<int> P;
	public:
	
	int maximumCycles(vector <string> tree1, vector <string> tree2, int K) {
		int i,j,k,x,y,z;
		T=tree1.size();
		this->K=K;
		FOR(x,T) FOR(y,T) dist[0][x][y]=(tree1[x][y]=='X')?1:100;
		FOR(x,T) FOR(y,T) dist[1][x][y]=(tree2[x][y]=='X')?1:100;
		FOR(x,T) dist[0][x][x]=dist[1][x][x]=0;
		FOR(i,T) FOR(j,T) FOR(k,T) dist[0][j][k] = min(dist[0][j][k], dist[0][j][i]+dist[0][i][k]);
		FOR(i,T) FOR(j,T) FOR(k,T) dist[1][j][k] = min(dist[1][j][k], dist[1][j][i]+dist[1][i][k]);
		P.clear();
		FOR(i,T) P.push_back(i);
		
		int ma=0;
		do{
			//select2
			int res=0;
			FOR(x,T) for(y=x+1;y<T;y++) {
				if(2+dist[0][x][y]+dist[1][P[x]][P[y]]==K) res++;
			}
			ma=max(ma,res);
		}while(next_permutation(P.begin(),P.end()));
		
		return ma;
	}
};

まとめ

これはさっくり解けて良かった。