POJ-2965: The Pilots Brothers' refrigerator
keyword
ライツアウト BruteForce C++
問題概要
ルールの少し変わったサイズ4*4のボードでのライツアウト。最小手数を出力する問題。
解法
16マスしかないのでBruteForceでもギリギリ間に合いそう。このルールだと計算量はO(2^22)で間に合いそうだと思ったらTLEした。その後小手先の高速化で通った。
感想
連立1次方程式で解いた場合も最小性は保たれているんだろうか。真面目に考えてないけど、答えが存在する場合は最小になっている気がする。そもそも行列のrankはどうなっているんだろう。ちょっと前SRMのhardで出題されていた気がする。
#include <cstdio> using namespace std; char board[10][10]; char tmp[10][10]; bool check(int bit){ for(int i=0; i<4; i++)for(int j=0; j<4; j++) tmp[i][j]=board[i][j]; for(int i=0; i<4; i++)for(int j=0; j<4; j++)if((bit>>(i*4+j))&1){ for(int k=0; k<4; k++) tmp[i][k] = tmp[i][k]=='-'?'+':'-'; for(int k=0; k<4; k++) tmp[k][j] = tmp[k][j]=='-'?'+':'-'; tmp[i][j] = tmp[i][j]=='-'?'+':'-'; } for(int i=0; i<4; i++)for(int j=0; j<4; j++) if(tmp[i][j] == '+') return false; return true; } void solve(){ int ans = 0; if(check(0)) goto end; for(int k=1;k<=16;k++){ int comb = (1<<k) - 1; while(comb < 1<<16){ if(check(comb)){ ans = comb; goto end; } int x = comb & -comb, y = comb + x; comb = ((comb & ~y) / x >> 1) | y; } } end:; printf("%d\n",__builtin_popcount(ans)); for(int i=0; i<4; i++)for(int j=0; j<4; j++)if((ans>>(i*4+j))&1){ printf("%d %d\n",i+1,j+1); } } int main(){ for(int i=0; i<4; i++) gets(board[i]); solve(); return 0; }