Poj 1753 Flip Game 高斯消元
题目连接:
http://poj.org/problem?id=1753
题目大意:
有一个4*4的方格,每个格子是黑色或者白色,每翻转其中一个格子使其变色,将会带动其上下左右的格子同时发生变色,问最终至少要翻转几个格子才能使4*4的方格变成同一种颜色?
解题思路:
其实这个题目怎么搞都可以,可以暴搜,位运算,dfs,最近在学高斯消元,就用高斯解一下,16个格子增广矩阵列为16*17,求出阶梯矩阵后,枚举不确定变元,根据不确定变元和阶梯矩阵求出确定变元,然后统计需要操作的次数,选择最优即可。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <iostream> 6 using namespace std; 7 8 const int maxn = 20; 9 int det[maxn][maxn], equ, var; 10 11 int gauss () 12 { 13 int max_i, k, col, cou = 0; 14 int free_num[maxn], free_i[maxn], x[maxn]; 15 16 memset (free_i, 0, sizeof(free_i)); 17 memset (x, 0, sizeof(x)); 18 19 for (k=col=0; k<equ&&col<var; k++, col++) 20 {//转化为阶梯矩阵 21 max_i = k; 22 for (int i=k+1; i<equ; i++)// 找到该col列元素绝对值最大的那行与第k行交换. 23 if (det[max_i][col] < det[i][col]) 24 max_i = i; 25 if (det[max_i][col] == 0) 26 {// 说明该col列第k行以下全是0了,则处理当前行的下一列. 27 free_i[col] = 1; 28 x[cou++] = col; 29 k --; 30 continue; 31 } 32 if (max_i != k) 33 for (int i=col; i<=var; i++) 34 swap(det[max_i][i], det[k][i]); 35 for (int i=k+1; i<equ; i++) 36 if (det[i][col])// 枚举要删去的行. 37 for (int j=col; j<=var; j++) 38 det[i][j] ^= det[k][j]; 39 } 40 for (int i=k; i<equ; i++) 41 if (det[i][var])//判断是否有解 42 return maxn; 43 int res = maxn, num = 1<<cou; 44 for (int i=0; i<num; i++) 45 { 46 int nu = 0, m = i; 47 memset (free_num, 0, sizeof(free_num)); 48 for (int j=0; j<cou; j++) 49 {//枚举不确定变元 50 if (m % 2) 51 { 52 free_num[x[j]] = 1; 53 nu ++; 54 } 55 m /= 2; 56 } 57 for (int j=k-1; j>=0; j--) 58 if (!free_i[j]) 59 {//根据不确定变元,计算确定变元 60 int temp = det[j][16]; 61 for (int l=j+1; l<var; l++) 62 if (det[j][l]) 63 temp ^= free_num[l]; 64 free_num[j] = temp; 65 if (temp) 66 nu ++; 67 } 68 res = min (res, nu); 69 } 70 return res; 71 } 72 int main () 73 { 74 int map[maxn], j = 0; 75 char str[maxn]; 76 77 equ = var = 16; 78 for (int i=0; i<4; i++) 79 { 80 scanf ("%s", str); 81 for (int l=0; str[l]; l++) 82 if (str[l] == 'b') 83 map[j++]=1; 84 else 85 map[j++] = 0; 86 } 87 88 memset (det, 0, sizeof(det)); 89 for (int i=0; i<16; i++) 90 {//把方格转化为增广矩阵 91 det[i][i] = 1; 92 det[i][16] = map[i]; 93 if (i < 12) 94 det[i][i+4] = 1; 95 if (i > 3) 96 det[i][i-4] = 1; 97 if (i % 4 != 0) 98 det[i][i-1] = 1; 99 if (i % 4 != 3) 100 det[i][i+1] = 1; 101 } 102 int res = gauss (); 103 memset (det, 0, sizeof(det)); 104 for (int i=0; i<16; i++) 105 { 106 det[i][i] = 1; 107 det[i][16] = 1 - map[i]; 108 if (i < 12) 109 det[i][i+4] = 1; 110 if (i > 3) 111 det[i][i-4] = 1; 112 if (i % 4 != 0) 113 det[i][i-1] = 1; 114 if (i % 4 != 3) 115 det[i][i+1] = 1; 116 } 117 res = min (res, gauss()); 118 if (res == maxn) 119 printf ("Impossible\n"); 120 else 121 printf ("%d\n", res); 122 return 0; 123 }
顺便再贴一个暴搜代码,简单粗暴,清晰明了
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 7 #define N 5 8 #define INF 0x3f3f3f 9 using namespace std; 10 11 char a[N][N], map[N][N]; 12 int dir[][2] = {0,0, 1,0, 0,1, -1,0, 0,-1}; 13 14 int change(char ch, int num); 15 void turn (int x, int y, char X[][N]); 16 void init (); 17 18 int main () 19 { 20 int i, j, min, sum, num; 21 22 for (i=0; i<4; i++) 23 { 24 scanf ("%s", a[i]); 25 strcpy (map[i], a[i]); 26 } 27 28 min = INF; 29 30 for (i=0; i<16; i++) 31 { 32 sum = i; 33 num = 0; 34 for (j=0; j<4; j++) 35 { 36 if ( sum % 2 ) 37 { 38 turn(0, j, map); 39 num ++; 40 } 41 sum /= 2; 42 } 43 44 init(); 45 sum = change ('b', num); 46 if (min > sum) 47 min = sum; 48 init(); 49 sum = change ('w', num); 50 if (min > sum) 51 min = sum; 52 53 sum = i; 54 for (j=0; j<4; j++) 55 { 56 if ( sum % 2 ) 57 { 58 turn (0, j, map); 59 } 60 sum /= 2; 61 } 62 } 63 if (min == INF) 64 printf ("Impossible\n"); 65 else 66 printf ("%d\n", min); 67 return 0; 68 } 69 int change( char ch, int num) 70 { 71 int i, j; 72 73 for (i=1; i<4; i++) 74 for (j=0; j<4; j++) 75 if (a[i-1][j] != ch) 76 { 77 num ++; 78 turn(i, j, a); 79 } 80 for (i=0; i<4; i++) 81 if (a[3][i] != ch) 82 return INF; 83 return num; 84 } 85 86 void turn (int x, int y, char X[][N]) 87 { 88 for (int i=0; i<5; i++) 89 { 90 int A = x + dir[i][0]; 91 int B = y + dir[i][1]; 92 93 if (A >= 0 && A < 4 && B >= 0 && B < 4) 94 { 95 if (X[A][B] == 'w') 96 X[A][B] = 'b'; 97 else 98 X[A][B] = 'w'; 99 } 100 } 101 } 102 103 void init () 104 { 105 int i; 106 for (i=0; i<4; i++) 107 strcpy (a[i], map[i]); 108 }
本文为博主原创文章,未经博主允许不得转载。