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('
');
69         }
70     }
71     return 0;
72 }
原文地址:https://www.cnblogs.com/WABoss/p/4937658.html