POJ3279 Fliptile(暴力)
有一种暴力是这样的,枚举一边,确定另一边。
这一题是这么解的,枚举第一行所有翻转情况,然后剩下几行其实是确定的,因为前i行翻转方式确定后只能通过第i+1行的翻转来改变第i行的状态,于是依次模拟求出剩下几行的翻转情况。
另外其实每个点最多只会被翻转一次,因为如果翻转两次和不翻转是一样的。
这题很有意思。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 int n,m,sta[16][16],op[16][16]; 6 7 void flip(int x,int y){ 8 int dx[4]={0,0,1,-1}; 9 int dy[4]={1,-1,0,0}; 10 11 sta[x][y]^=1; 12 for(int i=0; i<4; ++i){ 13 int nx=x+dx[i],ny=y+dy[i]; 14 if(nx<0 || nx>=n || ny<0 || ny>=m) continue; 15 sta[nx][ny]^=1; 16 } 17 } 18 bool isOK(){ 19 for(int i=0; i<n; ++i){ 20 for(int j=0; j<m; ++j) if(sta[i][j]) return 0; 21 } 22 return 1; 23 } 24 int doit(){ 25 int cnt=0; 26 for(int i=0; i<n-1; ++i){ 27 for(int j=0; j<m; ++j){ 28 if(sta[i][j]){ 29 flip(i+1,j); 30 op[i+1][j]=1; 31 ++cnt; 32 } 33 } 34 } 35 if(isOK()) return cnt; 36 else return 10000; 37 } 38 int main(){ 39 int init[16][16],ans[16][16]; 40 scanf("%d%d",&n,&m); 41 for(int i=0; i<n; ++i){ 42 for(int j=0; j<m; ++j) scanf("%d",&init[i][j]); 43 } 44 int res=10000; 45 for(int i=0; i<(1<<m); ++i){ 46 memcpy(sta,init,sizeof(init)); 47 memset(op,0,sizeof(op)); 48 int cnt=0; 49 for(int j=0; j<m; ++j){ 50 if((i>>j)&1){ 51 flip(0,m-j-1); 52 op[0][m-j-1]=1; 53 ++cnt; 54 } 55 } 56 cnt+=doit(); 57 if(res>cnt){ 58 res=cnt; 59 memcpy(ans,op,sizeof(op)); 60 } 61 } 62 if(res==10000) puts("IMPOSSIBLE"); 63 else{ 64 for(int i=0; i<n; ++i){ 65 for(int j=0; j<m; ++j){ 66 printf("%d ",ans[i][j]); 67 } 68 putchar('\n'); 69 } 70 } 71 return 0; 72 }