kmjp's blog

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

TopCoder SRM 582 Div2 Hard ColorTheCells

Div1 Mediumがまだ解けてないので先にDiv2 Hardでも。
http://community.topcoder.com/stat?c=problem_statement&pm=12581

問題

以下の条件において、1列に並んだ0~(N-1)番のNマスのセルにペンキを塗りたい。

  • 初期状態で塗る人は0番のマスにいる。
  • 1マス移動すると1の時間がかかる。
  • 今立っているマスの隣のマスに1の時間をかけてペンキを塗ることができる。
  • 各マスについて、ペンキを塗り始めてから乾くまでの時間が与えられる。乾くまではそのマスの上は歩けない。

全部のマスが塗り終わるまでの最短時間を求めよ(乾き終わるのは待たなくて良い)。

解法

N<=7とNが小さい。
よって例によって塗る順番をN!パターン全部試せばよい。
また、各マスを左と右どちらから塗るかでパターンが変わるけど、両端を除く(N-2)マスについて両側試せばよい。
計算量はO(N! * 2^N)程度だけどN<=7なので余裕。

class ColorTheCells {
	
	vector<int> D;
	int N;
	public:
	
	int dodo2(vector<int>& V, int mask) {
		int i;
		int pt[10];
		int ret=0,ret2;
		
		FOR(i,N) pt[i]=-1;
		int cur=0;
		FOR(i,N) {
			int tar=V[i] + ((mask&(1<<V[i]))?-1:1);
			
			while(cur<tar) {
				cur++;
				ret=max(ret+1,pt[cur]+1);
			}
			while(cur>tar) {
				cur--;
				ret=max(ret+1,pt[cur]+1);
			}
			
			cur=tar;
			ret++;
			pt[V[i]]=ret+D[V[i]];
		}
		return ret;
	}
	
	int dodo(vector<int>& V) {
		int mask;
		int mi=1000000000;
		FOR(mask,1<<N) {
			if(mask&1) continue;
			if((mask&(1<<(N-1)))==0) continue;
			mi=min(mi,dodo2(V,mask));
		}
		return mi;
	}
	
	int minimalTime(vector <int> dryingTime) {
		int i;
		vector<int> V;
		
		D=dryingTime;
		N=D.size();
		FOR(i,N) V.push_back(i);
		int mi=1000000000;
		do {
			mi=min(mi,dodo(V));
		} while(next_permutation(V.begin(),V.end()));
		
		return mi;
	}
};

まとめ

next_permutation便利だね。使い方に慣れなかったけど、ようやくそらで書けるようになった。
なんか最近TreeUnionDiv2といいMarblePositioningといいDiv2 Hardで全探索系多くない?
あとDiv2 hardは最近難易度が若干低下している気がする。数回前のSRMとかかなりきつかったのに、最近は自分でもすぐ解法が思いつく。