Fliptile POJ - 3279(状态压缩)
题意:给你一个n * m的矩阵,元素为0/1, 求把所有的元素变成0所需要的最少操作。(每对一个格子操作,该十字格的元素反转)
分析:一看数据量 <= 15, 就有点状态压缩的感jio。从小到大枚举第一行的操作,因为第一行的操作决定了后面所有的操作,所以最后判断对于第一行的操作是不是符合题意即可。
代码:
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 using namespace std; 6 const int maxn = 20; 7 int now; 8 int g[maxn][maxn]; 9 int cnt[maxn][maxn]; 10 int res[(1 << 15) + 10][maxn][maxn]; 11 12 int main() 13 { 14 int n, m; cin >> n >> m; 15 for (int i = 1; i <= n; i++) 16 for (int j = 1; j <= m; j++) 17 cin >> g[i][j]; 18 int minn = 1e9; 19 for (now = 0; now < (1 << m); now++) 20 { 21 int tmp = now; 22 int ope = 0; 23 memset(cnt, 0, sizeof(cnt)); 24 for (int i = m; i >= 1; i--) 25 { 26 if (tmp & 1) 27 { 28 ope++; 29 cnt[1][i]++, cnt[2][i]++; 30 if (i >= 2) cnt[1][i - 1]++; 31 if (i <= m - 1) cnt[1][i + 1]++; 32 res[now][1][i]++; 33 } 34 tmp >>= 1; 35 } 36 for(int i = 2; i <= n; i++) 37 for (int j = 1; j <= m; j++) 38 { 39 if ((g[i - 1][j] + cnt[i - 1][j]) & 1) 40 { 41 ope++; 42 cnt[i][j]++, cnt[i - 1][j]++, cnt[i + 1][j]++; 43 if (j >= 2) cnt[i][j - 1]++; 44 if (j <= m - 1) cnt[i][j + 1]++; 45 res[now][i][j]++; 46 } 47 } 48 int flag = 0; 49 for(int i = 1; i <= m; i++) 50 if ((g[n][i] + cnt[n][i]) & 1) 51 { 52 flag = 1; 53 break; 54 } 55 if (!flag) 56 res[now][0][0] = ope, minn = min(minn, ope); 57 else res[now][0][0] = -1; 58 } 59 for(int i = 0; i < (1 << 15); i++) 60 if (res[i][0][0] == minn) 61 { 62 for (int j = 1; j <= n; j++) 63 for (int k = 1; k <= m; k++) 64 printf("%d%c", res[i][j][k], k == m ? '\n' : ' '); 65 return 0; 66 } 67 printf("IMPOSSIBLE"); 68 }