题目描述:一个n*n的网格图,每一格是白色和黄色任意一种颜色,你点击一个格子的时候,这个格子和它上下左右四周的格子都变色(黄->白或者
白->黄),现在给你一个初始的图,问你最少需要点多少次能使这个图的颜色编程全黄的。 n
<= 15
高斯消元(貌似可能有错误的情况,但是能过此题,而且思路很巧妙,不妨总结一下):
把n*n个格子看成n*n个变量,系数矩阵为A,答案矩阵为B,A
* X = B, A[i][j] = 1当且仅当第j个格子变化会影响到第i个格子变化。B[i] =
1表示第i个格子开始时不是黄色(即第i个格子最后的结果是要变化)。
比如
3
yyy
yyy
yyy
系数矩阵为
结果矩阵为
1 1 0 1 0 0 0 0
0 0
1 1 1 0 1 0 0 0
0
0
0 1 1 0 0 1 0 0
0
0
1 0 0 1 1 0 1 0
0
0
0 1 0 1 1 1 0 1
0
0
0 0 1 0 1 1 0 0
1
0
0 0 0 1 0 0 1 1
0
0
0 0 0 0 1 0 1 1
1
0
0 0 0 0 0 1 0 1
1
0
第一行为例:能影响到第一个格子变化的有,第1个,第2个,第4个(2行1列为第四个)。
结果为0说明能影响到第一个格子变化的总和为2的倍数,即不会变化。
因此解次方程组,结果为1的表示这个格子需要变化,统计有几个格子需要变化就是答案。
#include<iostream>
#include<cmath>
using namespace std;
#define N 225
#define M 225
typedef int zzy;
zzy fab(zzy x) {return (x > 0 ? x : -x);}
void swap(zzy &x, zzy &y) { zzy
temp = x; x = y; y = temp;}
zzy A[N][M 1]; //N 行 M 1列:多出来的一列是答案b列,增广矩阵
int move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int gaos(int r, int c)// c 为系数矩阵实际的列数,不带最后一列的增广部分
{
int i = 0, j
= 0;
while(i
< r && j
< c)
{
int id = i;
for(int k = i 1; k < r; k )
if (fab(A[k][j]) > fab(A[id][j]))
id = k;
zzy temp;
if (A[id][j] != 0)
{
temp = A[id][j];
for(int k = j; k < c 1; k )
swap(A[id][k], A[i][k]);
for(int k = i 1; k < r; k )
if (A[k][j] != 0)
for(int l = j; l < c 1; l )
A[k][l] = A[k][l] ^ A[i][l];
i ;
}
j ;
}
for(int k =
i; k < r; k )
if (A[k][c] != 0)
return -1; // 无解
int cnt =
A[r - 1][c];
for(i = r -
2; i >= 0; i--)
{
for(j = i 1; j < r; j )