题意:给一个5*6的矩阵
1代表该位置的灯亮着, 0代表该位置的灯没亮
按某个位置的开关,可以同时改变 该位置 以及 该位置上方、下方、左方、右方, 共五个位置的灯的开、关(1->0, 0->1)
问能否将所有的灯关闭 若能 输出需要按哪些地方; 不能输出-1
高斯消元的入门题。
每个位置可以列出一个方程, 列出增广矩阵:
每个位置可以形成增广矩阵的一行, 每行都有30个系数 分别代表(0到29号灯), 将 可以影响该位置改变的 位置(自己、上、下、左、右)对应的置1, 其余置0
这样就形成了30*30的系数矩阵。
将初始状态置入最后一列 就形成了增广矩阵
接下来只要解方程组即可。
化成约化阶梯后最后一列即为该方程组的解。
P.s. 需要注意的是:因为是矩阵表示的是灯的开关状态,所以解的过程中不应出现0、1以外的其余数字 即 01方程 用异或求解
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 int a[300][300]; // 增广矩阵 2 int x[300]; // 解 3 int free_x[300]; // 标记是否为自由未知量 4 5 int n, m; 6 void debug() 7 { 8 for(int i=0;i<n*n;i++) 9 { 10 for(int j=0;j<n*n;j++) 11 printf("%d ", a[i][j]); 12 printf("\n"); 13 } 14 } 15 16 void Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列 17 { 18 //转换为阶梯形式 19 int col=0, k, num=0; 20 for(k=0;k<n && col<m;k++, col++) 21 {//枚举行 22 int max_r=k; 23 for(int i=k+1;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换 24 if(abs(a[i][col])>abs(a[max_r][col])) 25 max_r=i; 26 if(max_r!=k)// 与第k行交换 27 for(int j=col;j<m+1;j++) 28 swap(a[k][j], a[max_r][j]); 29 if(!a[k][col])// 说明该col列第k行以下全是0了 30 { 31 k--; 32 free_x[num++]=col; 33 continue; 34 } 35 for(int i=k+1;i<n;i++)// 枚举要删除的行 36 if(a[i][col]) 37 for(int j=col;j<m+1;j++) 38 a[i][j]^=a[k][j]; 39 } 40 41 // debug(); 42 // printf("%d %d\n", col, k); 43 // 44 // for(int i=k;i<n;i++) 45 // if(a[i][col]) 46 // return -1; // 无解 47 48 // if(k<m) //m-k为自由未知量个数 49 // { 50 // int stat=1<<(m-k); 51 // int ans=INT_MAX; 52 // for(int i=0;i<stat;i++) 53 // { 54 // int cnt=0; 55 // for(int j=0;j<m-k;j++) 56 // if(i&(1<<j)) 57 // { 58 // x[free_x[j]]=1; 59 // cnt++; 60 // } 61 // else 62 // x[free_x[j]]=0; 63 // for(int j=k-1;j>=0;j--) 64 // { 65 // int tmp; 66 // for(tmp=j;tmp<m;tmp++) 67 // if(a[j][tmp]) 68 // break; 69 // x[tmp]=a[j][m]; 70 // for(int l=tmp+1;l<m;l++) 71 // if(a[j][l]) 72 // x[tmp]^=x[l]; 73 // cnt+=x[tmp]; 74 // } 75 // if(cnt<ans) 76 // ans=cnt; 77 // } 78 // return ans; 79 // } 80 // 81 // 唯一解 回代 82 for(int i=m-1;i>=0;i--) 83 { 84 x[i]=a[i][m]; 85 for(int j=i+1;j<m;j++) 86 x[i]^=(a[i][j] && x[j]); 87 } 88 // int ans=0; 89 // for(int i=0;i<n*n;i++) 90 // ans+=x[i]; 91 // return ans; 92 } 93 94 95 void init() 96 { 97 n=5, m=6; 98 memset(a, 0, sizeof(a)); 99 memset(x, 0, sizeof(x)); 100 for(int i=0;i<n;i++) 101 for(int j=0;j<m;j++) 102 { 103 int t=i*m+j; 104 a[t][t]=1; 105 if(i>0) 106 a[(i-1)*m+j][t]=1; 107 if(i<n-1) 108 a[(i+1)*m+j][t]=1; 109 if(j>0) 110 a[i*m+j-1][t]=1; 111 if(j<m-1) 112 a[i*m+j+1][t]=1; 113 } 114 } 115 116 int main() 117 { 118 int t, ca=1; 119 scanf("%d", &t); 120 while(t--) 121 { 122 init(); 123 for(int i=0;i<n*m;i++) 124 scanf("%d", &a[i][n*m]); 125 printf("PUZZLE #%d\n", ca++); 126 Gauss(n*m, n*m); 127 for(int i=0;i<n;i++) 128 for(int j=0;j<m;j++) 129 { 130 printf("%d", x[i*m+j]); 131 if(j==5) 132 printf("\n"); 133 else 134 printf(" "); 135 } 136 } 137 return 0; 138 }