kmjp's blog

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

TopCoder SRM 732 Div2 Hard TheFlippingGame2

Div1EasyよりDiv2Hardが簡単ってどういうこった。
https://community.topcoder.com/stat?c=problem_statement&pm=14844

問題

2次元グリッドが与えられる。
各マスは

  • 埋まっていない
  • 白いタイルで埋まっている
  • 黒いタイルで埋まっている

のいずれかである。

まず最初に、埋まってないマスを白黒いずれかのマスですべて埋める。
ただし埋める色は全マス同色でなければならない。

その後、あるマスを選択すると、隣接マスで連結する同色のマスをすべて白黒反転する、ということを繰り返す。
全マス同色にするには何回マス選択処理が必要か。

解法

埋める色に関しては白黒2パターン両方試せばよい。
連結成分の色を反転させて全マスの色をそろえるにはテクがあり、1つのマスを選んだら、全マス同色になるまでそこを選択・反転し続けることである。
異なる色の隣接マスの移動コストを1としたとき、全マス同色になるまでの処理回数は、選択したマスから移動するのにコスト最大のマスで決まる。
よってこれはマス間の移動距離を求める問題に還元でき、ダイクストラ法で求めることができる。

問題はどのマスを選択するかだが、元のマス数が少ないので全マスで試せばよい。

class TheFlippingGame2 {
	public:
	int hoge(int H,int W,vector<string> S) {
		int mi=10101;
		int sy,sx,x,y;
		FOR(sy,H) FOR(sx,W) {
			int D[20][20];
			FOR(y,H) FOR(x,W) D[y][x]=4040;
			priority_queue<pair<int,int>> Q;
			D[sy][sx]=0;
			Q.push({0,sy*100+sx});
			int ma=0;
			while(Q.size()) {
				int co=-Q.top().first;
				int cy=Q.top().second/100;
				int cx=Q.top().second%100;
				Q.pop();
				if(co!=D[cy][cx]) continue;
				ma=max(ma,co);
				
				int d[4]={1,0,-1,0},i;
				FOR(i,4) {
					int ty=cy+d[i];
					int tx=cx+d[i^1];
					if(ty<0||ty>=H||tx<0||tx>=W) continue;
					if(D[ty][tx]>co+(S[cy][cx]!=S[ty][tx])) {
						D[ty][tx]=co+(S[cy][cx]!=S[ty][tx]);
						Q.push({-D[ty][tx],ty*100+tx});
					}
				}
			}
			mi=min(mi,ma);
		}
		
		
		return mi+1;
	}
	
	int MinimumMoves(int n, int m, vector <string> x) {
		string S="bw";
		int mi=101010;
		FORR(c,S) {
			vector<string> y=x;
			FORR(s2,y) FORR(c2,s2) if(c2=='e') c2=c;
			mi=min(mi,hoge(n,m,y));
		}
		return mi;
	}
}

まとめ

面白い設定ではあるけども。