$dp[y][bit_p][bit_c]=$ 현재 $y$ row에 있고 이전 행의 비트가 $bit_p$ 이고 현재 행의 비트가 $bit_c$ 일 때 끝까지 모두 켜기 위해 더 필요한 최솟값
이라고 정의하면 된다.
$O(n2^m2^m2^m)$ 이 될 것 같지만 백트랙킹이 적절히 되어 시간안에 돈다.
DP를 안 쓰고 푸는게 정해인것같다.
십자가로 조작되는 문제는 첫 행을 결정하면 그 다음 행이 항상 결정되므로 브루트포스가 됨은 알고 있었는데 인접한 9칸이 모두 조작되는 문제는 처음본것같아 그냥 DP로 풀었다.
정해는 동일하게 첫 행은 모두 브루트포스로 경우의 수를 따져보고 두 번째 행부터는 $y-1,x-1$ 칸의 전구가 꺼져있다면 항상 $y,x$ 칸을 조작하는 것으로 가능한지 검사하는 방식으로 풀리는 것 같다.
constintdy[]={-1,-1,0,1,1,1,0,-1,0},dx[]={0,1,1,1,0,-1,-1,-1,0},op[]={4,5,6,7,0,1,2,3};intdp[8][256][256];constintinf=1e9;voidsolve(){memset(dp,-1,sizeofdp);intY,X;cin>>Y>>X;vsb(Y);fv(b);virow_bit(Y);for(inty=0;y<Y;y++){for(intx=0;x<X;x++){if(b[y][x]=='*')row_bit[y]|=(1<<x);}}debug(row_bit);// 현재 row, 이전 row의 상태, 현재 row의 상태 function<int(int,int,int)>fn=[&](inty,intb,intc)->int{debug(y,b,c);if(y==Y){if(b==(1<<X)-1)return0;returninf;}int&ret=dp[y][b][c];if(~ret)returnret;ret=inf;for(intmask=0;mask<(1<<X);mask++){intprev=b,current=c,nxt=y==Y-1?0:row_bit[y+1];intadd=0;for(intx=0;x<X;x++){if(mask&(1<<x)){add++;for(intd=0;d<9;d++){intny=y+dy[d];intnx=x+dx[d];if(ny>=0&&ny<Y&&nx>=0&&nx<X){if(ny==y-1){prev^=1<<nx;}elseif(ny==y){current^=1<<nx;}else{nxt^=1<<nx;}}}}}if(prev==(1<<X)-1||y==0){mina(ret,add+fn(y+1,current,nxt));}}returnret;};intret=fn(0,0,row_bit[0]);if(ret==inf)cout<<-1;elsecout<<ret;}
Comments