高斯消元
题意:
给你一个5*6的矩阵,每个点上都有一个灯,按下f[i][j]的按钮,f[i][j]位置的灯的状态会改变,它上下左右的灯的状态也会改变(开变关,关变开)。
现在给出这个矩阵的初始状态,输出按下哪些按钮,使所有的灯都关闭。
分析:
每个位置可以形成增广矩阵的一行,每行有30个系数分别代表0 -29号灯,将可以影响该位置变换的位置(自己,上,下,左,右)置1,其余的置0;这样就形成了30*30的系数矩阵,将初始状态置入最后一列,就形成了增广矩阵。
高斯消元解矩阵的秩,本题认为有唯一解。
代码:
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 50; //未知数数目
int equ, var; //equ个方程,var个变元
int a[MAXN][MAXN]; //行数为equ,0~var列为系数,var列为得数
int x[MAXN]; //解集
int free_num; //自由变元数量
int free_x[MAXN]; //自由变元,多解枚举时会用到
/*******************************************************
* mod2高斯消元过程
* 返回-1无解,0惟一解,>0自由变元数目
*******************************************************/
int Gauss()
{
int maxr, col, i, j, k;
free_num = 0;
for (k = 0, col = 0; k<equ && col<var; k++, col++)
{
maxr = k;
for (i = k + 1; i<equ; i++)
{
if (abs(a[i][col])>abs(a[maxr][col]))
maxr = i;
}
if (a[maxr][col] == 0)
{
k--;
free_x[free_num++] = col; //出现一个自由变元
continue;
}
if (maxr != k)
{
for (j = col; j<var + 1; j++)
swap(a[k][j], a[maxr][j]);
}
for (i = k + 1; i<equ; i++)
{
if (a[i][col] != 0)
{
for (j = col; j<var + 1; j++)
a[i][j] ^= a[k][j];
}
}
}
for (i = k; i<equ; i++)
if (a[i][col] != 0)
return -1; //无解情况
if (k<var)
return var - k; //多个自由变元
for (i = var - 1; i >= 0; i--) //惟一解,进行回代
{
x[i] = a[i][var];
for (j = i + 1; j<var; j++)
x[i] ^= (a[i][j] && x[j]);
}
return 0;
}
void work()
{
int i, j, k, t;
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
equ = 30;
var = 30;
for (i = 0; i<5; i++)
for (j = 0; j<6; j++)
{
t = i * 6 + j;
a[t][t] = 1; //itself
if (i > 0) a[(i - 1) * 6 + j][t] = 1; //top
if (i < 4) a[(i + 1) * 6 + j][t] = 1; //bottom
if (j > 0) a[i * 6 + j - 1] [t] = 1; //left
if (j < 5) a[i * 6 + j + 1] [t] = 1; //right
}
for (i = 0; i < 30; i++)
scanf("%d",&a[i][30]);
Gauss();
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
printf("%d ", x[6 * i + j]);
printf("%d\n",x[6*i+5]);
}
}
int main()
{
int i, T;
scanf("%d", &T);
for (i = 1; i <= T; i++)
{
printf("PUZZLE #%d\n", i);
work();
}
return 0;
}