ちょっと苦戦。
http://yukicoder.me/problems/no/460
問題
H*Wのフィールドがあり、各マス0,1が埋められている。
あるマスを選択すると、そのマスと周囲8マスの01が反転する。
全マスを0にするには最小何個のマスを選択すればよいか。
解法
よくあるライツアウトに似ているが、反転する領域が異なる。
まず1行目の選択の仕方を2^W通り総当たりしよう。
以後2行目以降の選択の仕方を決めていくが、その際1つ上の行がすべて0になるような決め方をしなければならない。
また、そのような決め方が複数ある場合、選択するマス数が最小のものを選ぶ。
あとはそのように2~H行目の選択の仕方を決めていき、最終的に全マスが0になるかチェックすればよい。
前処理として、ある行の状態に対し、それらをすべて0にする最小選択マス数を先に列挙しておくと楽。
int H,W; int A[10]; int B[10]; int mask[1<<8]; int rev[1<<8]; void solve() { int i,j,k,l,r,x,y; string s; cin>>H>>W; FOR(y,H) FOR(x,W) cin>>r, A[y] |= r<<x; FOR(i,1<<W) rev[i]=101010; FOR(i,1<<W) { FOR(x,W) if(i&(1<<x)) { if(x) mask[i] ^= 1<<(x-1); mask[i] ^= 1<<x; if(x<W-1) mask[i] ^= 1<<(x+1); } rev[mask[i]]=min(rev[mask[i]],__builtin_popcount(i)); } int ma=101010; FOR(i,1<<W) { FOR(y,H) B[y]=A[y]; B[0] ^= mask[i]; B[1] ^= mask[i]; int tot=__builtin_popcount(i); for(y=1;y<H;y++) { int tar=B[y-1]; tot+=rev[tar]; B[y-1] ^= tar; B[y] ^= tar; B[y+1] ^= tar; } if(B[H-1]==0) ma=min(ma,tot); } if(ma==101010) _P("Impossible\n"); else _P("%d\n",ma); }
まとめ
ライツアウト系問題を解いたことがあったのに妙に手間取った。