/*
translation:
有6*5的开关,每次按下一个开关,与之相邻的4个开关状态也会随之改变。给定开始状态,求使得所有开关为0的方法
solution:
高斯消元法
首先,假设在开始状态的基础上按下第二行第二列的开关,相当与在原来矩阵的基础上加上矩阵
0 1 0 0 ... 0
1 1 1 0 ... 0
0 1 0 0 ... 0
. . . . . . .
. .
0 0 0 0 ... 0 设该矩阵为B[6*2+2]
则相当与方程组:L+x0*B[0]+x1*B[1]+...+xn*B[n]=0, 移项化为x0*B[0]+x1*B[1]+...+xn*B[n]=L,L为初始状态的矩阵
将矩阵化开即可得到30个等式组成的方程组,利用高斯消元求解即可得到每个xi的值
注意到矩阵中只有0,1.所以可以采用异或代替加减
note:
date:
2016.11.8
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int R = 5;
const int C = 6;
const int maxn = 300;
int equ, var;
int a[maxn][maxn];
int x[maxn];
int free_x[maxn];
int free_num;
int gauss()
{
int maxr, col, k;
free_num = 0;
for(k = 0, col = 0; k < equ && col < var; k++, col++){
maxr = k;
for(int 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(int i = col; i <= var; i++)
swap(a[k][i], a[maxr][i]);
}
//消元
for(int i = k+1; i < equ; i++){
if(a[i][col] != 0){
for(int j = col; j <= var; j++)
a[i][j] = a[i][j] ^ a[k][j];
}
}
}
for(int i = k; i < equ; i++)
if(a[k][col]) return -1;
if(k < var) return var-k; //返回自由变元的个数
//有唯一解,回代
for(int i = var-1; i >= 0; i--){
x[i] = a[i][var];
for(int j = i+1; j < var; j++)
x[i] ^= (a[i][j] && x[j]);
}
return 0;
}
int main()
{
//freopen("in.txt", "r", stdin);
int T, kase = 0;
scanf("%d", &T);
while(T--){
//init
memset(a, 0, sizeof(a));
memset(free_x, 0, sizeof(free_x));
memset(x, 0, sizeof(x));
equ = var = 30;
for(int i = 0; i < 5; i++){
for(int j = 0; j < 6; j++){
int t = i*6+j;
a[t][t] = 1;
if(i > 0) a[(i-1)*6+j][t] = 1;
if(i < 4) a[(i+1)*6+j][t] = 1;
if(j > 0) a[i*6+j-1][t] = 1;
if(j < 5) a[i*6+j+1][t] = 1;
}
}
for(int i = 0; i < 30; i++)
scanf("%d", &a[i][30]);
gauss();
printf("PUZZLE #%d\n", ++kase);
for(int i = 0; i < 5; i++){
for(int j = 0; j < 6; j++){
printf("%d%c", x[i*6+j], j+1 == 6 ? '\n' : ' ');
}
}
}
return 0;
}
poj1222(高斯消元)
最新推荐文章于 2022-10-21 23:14:10 发布