题意:给你一个4*4的矩阵,每个位置对应着一个状态(开或者关),然后如果你按动某一个位置,那么上下左右位置都会被影响二改变状态,问最少经过几次达到全开或者全馆的状态。
分析:其实对于每一个位置都可以列一个线性方程,构成一个方程组,a[i][j]就是表示按动j位置时对i位置有影响,然后对于方程组用高斯消元求解,然后对于存在自由元的情况需要枚举判断符合的个数,最后取最小值。
然后 就比搜索跑得快多了
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<string>
#include<iostream>
#define nmax 350
using namespace std;
const int inf = 0x3f3f3f3f;
int a[nmax][nmax];
int x[nmax];
int free_x[nmax];
char mp[nmax][nmax];
int equ, var;
int Gauss(){
int max_r;
int col = 0, num = 0;
int k;
for (int i = 0; i <= var; ++i) x[i] = free_x[i] = 0;
for (k = 0; k < equ && col < var; k++, col++){
max_r = k;
for (int i = k + 1; i<equ; i++){
if (abs(a[i][col])>abs(a[max_r][col])) max_r = i;
}
if (max_r != k){
for (int j = k; j < var + 1; j++) swap(a[k][j], a[max_r][j]);
}
if (a[k][col] == 0){
free_x[num++] = col;
k--; continue;
}
for (int i = k + 1; i < equ; i++){
if (a[i][col] != 0){
for (int j = col; j < var + 1; j++){
a[i][j] ^= a[k][j];;
}
}
}
}
for (int i = k; i < equ; ++i){
if (a[i][col] != 0) 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;
}
void init(){//初始化矩阵
memset(a, 0, sizeof a);
memset(x, 0, sizeof x);
for (int i = 0; i < 4;i++)
for (int j = 0; j < 4; j++){
int pos = i * 4 + j;
a[pos][pos] = 1;
if (i>0) a[(i - 1) * 4 + j][pos] = 1;
if (i < 3) a[(i + 1) * 4 + j][pos] = 1;
if (j>0) a[i * 4 + j - 1][pos] = 1;
if (j < 3) a[i * 4 + j + 1][pos] = 1;
}
}
void enum_freex(int n, int & ans){//记接的个数 可放主函数
//二进制枚举,相当于容斥的枚举,检查每个对应情况是否符合情况
int num = (1 << (n));
ans = 1e9 + 7;
for (int i = 0; i < num; ++i){
int cnt = 0;
for (int j = 0; j < n; ++j){
if (i&(1 << j)){
cnt++;
x[free_x[j]] = 1;
}
else x[free_x[j]] = 0;
}
for (int k = var - n - 1; k >= 0; --k){// 没有自由元的最下面一行
int index = 0;
for (index = k; k < var; index++){// 在当前行找到第一个非0自由元(如果存在的话)
if (a[k][index]) break;
}
x[index] = a[k][var];
for (int j = index + 1; j < var; ++j){// 向后依次计算出结果
if (a[k][j]) x[index] ^= x[j];
}
cnt += x[index]; // 如果结果为1,则统计
}
ans = min(ans, cnt);
}
}
int main(){
var = equ = 16;
for (int i = 0; i < 4; i++)
cin >> mp[i];
init();
for (int i = 0; i < 4;i++)
for (int j = 0; j < 4; j++){
if (mp[i][j] == 'b') a[i * 4 + j][16] = 1;
else a[i * 4 + j][16] = 0;
}
int ans1 = Gauss();
//cout << ans1 << endl;
if (ans1 == -1) ans1 = inf;//无解
else if (ans1 == 0){//一个解
int num = 0;
for (int i = 0; i < 16; i++)
num += x[i];
ans1 = num;
}
else{
int ans;
enum_freex(4, ans);
ans1 = ans;
}
//转化情况
init();
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++){
if (mp[i][j] == 'b') a[i * 4 + j][16] = 0;
else a[i * 4 + j][16] = 1;
}
int ans2 = Gauss();
//cout << ans2 << endl;
if (ans2 == -1) ans2 = inf;
else if (ans2 == 0){
int num = 0;
for (int i = 0; i < 16; i++)
num += x[i];
ans2 = num;
}
else{
int ans;
enum_freex(4, ans);
ans2 = ans;
}
if (ans1 == inf&&ans1 == ans2)
cout << "Impossible" << endl;
else{
//cout << ans1 << " " << ans2 << endl;
cout << min(ans1, ans2) << endl;
}
return 0;
}