题意:黑白的板,每次选择一个十字形翻转(十字板内黑白互换,若是边界则不管),求最小将原图变为全白的策略。

题解:枚举第一行翻转情况,2^c,然后验证,由于第一行确定了,后面就可以跟着确定了。

View Code
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 int map[20][20];
 6 int hit[20][20],ahit[20][20];
 7 int ans,r,c;
 8 const int inf=1<<30;
 9 void on(int x,int y)
10 {
11     hit[x][y]^=1;
12     map[x][y]^=1;
13     map[x-1][y]^=1;
14     map[x+1][y]^=1;
15     map[x][y+1]^=1;
16     map[x][y-1]^=1;
17 }
18 void solve(int k,int cnt)
19 {
20     if(cnt>=ans)
21         return;
22     int i;
23     if(k==r)
24     {
25         for(i=1;i<=c;i++)
26             if(map[r][i]!=0)
27                 break;
28         if(i<=c)
29             return;
30         ans=cnt;
31         memcpy(ahit,hit,sizeof(hit));
32         return;
33     }
34     for(int i=1;i<=c;i++)
35         if(map[k][i])
36             on(k+1,i),cnt++;
37     solve(k+1,cnt);
38     for(int i=1;i<=c;i++)
39         if(hit[k+1][i])
40             on(k+1,i);
41 }
42 void dfs(int k,int cnt)
43 {
44     if(cnt>=ans)
45         return;
46     else if(k==c+1)
47     {
48         solve(1,cnt);
49         return;
50     }
51     else
52     {
53         dfs(k+1,cnt);
54         on(1,k);
55         dfs(k+1,cnt+1);
56         on(1,k);
57     }
58 }
59 int main()
60 {
61     while(scanf("%d%d",&r,&c)!=EOF)
62     {
63         ans=inf;
64         for(int i=1;i<=r;i++)
65         {
66             for(int j=1;j<=c;j++)
67             {
68                 scanf("%d",&map[i][j]);
69                 hit[i][j]=0;
70             }
71         }
72         dfs(1,0);
73         if(ans==inf)
74             printf("IMPOSSIBLE\n");
75         else
76         {
77             for(int i=1;i<=r;i++)
78             {
79                 for(int j=1;j<=c;j++)
80                 {
81                     if(j!=1)
82                         printf(" ");
83                     printf("%d",ahit[i][j]);
84                 }
85                 printf("\n");
86             }
87         }
88     }
89     return 0;
90 }