poj 3279 Fliptile (搜索..暴力?)
http://poj.org/problem?id=3279
反转类问题.
有N*M个方格,每个上面有数字0或者1
操作一个方格,这个方格即其相邻的四个方格(有公共边)会改变状态(由0变1或者由1变0)
问至少需要多少次操作,所有的状态都为0
如果有多组,输出字典序小的那一组.
跟开关灯的那题相似.
因为每个开关灯的动作还影响其他相邻灯的状态.所以对于这种题,一般思路是,先定住一部分,再由已知定住的这部分去确定其他部分.
对于这道题而言
首先我们可以很容易发现,操作数为偶数和为0是等价的.
操作数为1和为奇数是等价的.
对于这道题而言,我们可以首先枚举第一行的状态,一共有 2<
然后如果 a[i-1][j]为1,因为i-1行的状态已经确定,无法改变,所以能影响到a[i-1][j]的只有a[i][j]
那么a[i][j]一定要操作一次
最后判断最后一行是否都为0,如果为0,表示这种情况是合法的
然后找到操作数最小的一组.
字典序的话,只要是枚举的时候按照数的大小顺序就可以保证.
学会了用memcpy函数.
1
2 #include<iostream>
3 #include<iomanip>
4 #include<cstdio>
5 #include<algorithm>
6 #include<cmath>
7 #include<cstring>
8 #include<string>
9 #include<map>
10 #include<set>
11 #include<queue>
12 #include<vector>
13 #include<stack>
14 #define y0 abc111qqz
15 #define y1 hust111qqz
16 #define yn hez111qqz
17 #define j1 cute111qqz
18 #define tm crazy111qqz
19 #define lr dying111qqz
20 using namespace std;
21 #define REP(i, n) for (int i=0;i<int(n);++i)
22 typedef long long LL;
23 typedef unsigned long long ULL;
24 const int N=20;
25 int a[N][N],ans[N][N],op[N][N];
26 int m,n;
27 int dirx[10]={0,0,0,-1,1};
28 int diry[10]={0,1,-1,0,0};
29 int rec[N][N];
30 void solve(int x,int y)
31 {
32 for ( int i = 0 ; i < 5 ; i++ )
33 {
34 int newx = x + dirx[i];
35 int newy = y + diry[i];
36 if (newx>=1&&newx<=m&&newy>=1&&newy<=n)
37 {
38 a[newx][newy]=a[newx][newy]^1;
39 }
40 }
41 }
42 bool on (int x,int y)
43 {
44 int res = a[x][y];
45 for ( int i = 0 ; i < 5 ; i++ )
46 {
47 int newx = x + dirx[i];
48 int newy = y + diry[i];
49 if (newx>=1&&newx<=m&&newy>=1&&newy<=n)
50 {
51 res = res+op[newx][newy];
52 }
53
54 }
55 return res&1;
56 }
57 int main()
58 {
59 cin>>m>>n;
60 int mi = 9999999;
61 memset(rec,0,sizeof(rec));
62 for ( int i = 1 ; i <= m ; i++ )
63 {
64 for (int j = 1 ; j <= n ; j++)
65 {
66 cin>>a[i][j];
67 }
68 }
69 bool flag = false;
70 for ( int i = 0 ; i < (1<<n); i++ ) //枚举第一行的好改变情况
71 {
72 int tmp=i;
73 int num=0;
74 memset(op,0,sizeof(op));
75 memset(ans,0,sizeof(ans));
76 int k = n;
77 while (tmp)
78 {
79 op[1][k]=tmp%2;
80 if (op[1][k]==1) num++;
81 tmp = tmp / 2;
82 k--;
83 }
84 // cout<<"********************"<<endl;
85 // for ( int i = 1 ; i <= n ; i++)
86 // {
87 // cout<<op[1][i]<<" ";
88 // }
89 // cout<<endl;
90 // cout<<"*************************"<<endl;
91
92
93 for ( int j = 2 ; j <= m ; j++ )
94 {
95 for ( int k = 1 ; k <= n ; k++ )
96 {
97 if (on(j-1,k))
98 {
99 op[j][k]=1;
100 num++;
101 }
102 }
103 }
104 bool ok = true;
105 for ( int j = 1 ; j <= n ; j++ )
106 {
107 if (on(m,j))
108 {
109 ok=false;
110 break;
111 }
112 }
113 if (ok)
114 {
115 flag = true;
116 if (num<mi)
117 {
118 mi = num;
119 memcpy(rec,op,sizeof(op));
120 // for ( int j = 1 ; j <= m ; j ++ )
121 // {
122 // for ( int k = 1 ; k <= n ; k++ )
123 // {
124 // rec[j][k]=ans[j][k];
125 // }
126 // }
127 }
128 }
129 }
130 if (flag)
131 {
132 for ( int i = 1 ; i <= m ; i++ )
133 {
134 cout<<rec[i][1];
135 for ( int j = 2 ; j <= n ; j++ )
136 {
137 cout<<" "<<rec[i][j];
138 }
139 cout<<endl;
140 }
141 }
142 else
143 {
144 printf("IMPOSSIBLE\n");
145 }
146
147 return 0;
148 }
149