The game “The Pilots Brothers: following the stripy elephant” has a quest where a player needs to open a refrigerator.
There are 16 handles on the refrigerator door. Every handle can be in one of two states: open or closed. The refrigerator is open only when all handles are open. The handles are represented as a matrix 4х4. You can change the state of a handle in any location [i, j] (1 ≤ i, j ≤ 4). However, this also changes states of all handles in row i and all handles in column j.
The task is to determine the minimum number of handle switching necessary to open the refrigerator.
Input
The input contains four lines. Each of the four lines contains four characters describing the initial state of appropriate handles. A symbol “+” means that the handle is in closed state, whereas the symbol “−” means “open”. At least one of the handles is initially closed.
Output
The first line of the input contains N – the minimum number of switching. The rest N lines describe switching sequence. Each of the lines contains a row number and a column number of the matrix separated by one or more spaces. If there are several solutions, you may give any one of them.
Sample Input
-+-- ---- ---- -+--
Sample Output
6 1 1 1 3 1 4 4 1 4 3 4 4
Source
题目大意:
给你一个 4∗4 的矩阵,每个格子只有两个状态 “+” 和 "−" ,现在要将初始状态转化为全部是 "−" 的,当翻转一个格子的时候,每个格子
对应的行和列都得进行翻转,输出最小步数以及如何翻转的步骤。
解题思路:
第一种方法:还是高斯消元,首先找出系数矩阵,然后进行高斯消元就好啦
My Code:
/**
2016 - 09 - 09 晚上
Author: ITAK
Motto:
今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 400;
const int MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
int equ, var;///equ个方程 var个变量
int a[MAXN][MAXN];///增广矩阵
int x[MAXN];///解集
int x_i[MAXN];
bool free_x[MAXN];///判断是不是自由变元
int free_num;///自由变元的个数
int Gauss()
{
int Max_r;///当前列绝对值最大的存在的行
///col:处理当前的列
int row,col = 0;
int free_x_num;
int free_index;
free_num = 0;
for(int i=0; i<=var; i++)
{
x[i] = 0;
free_x[i] = 1;
}
for(row=0; row<equ&&col<var; row++,col++)
{
Max_r = row;
for(int i=row+1; i<equ; i++)
if(abs(a[i][col]) > abs(a[Max_r][col]))
Max_r = i;
if(a[Max_r][col] == 0)
{
free_x[col] = 1;
x_i[free_num++] = col;
row--;
continue;
}
if(Max_r != row)
for(int i=col; i<var+1; i++)
swap(a[row][i], a[Max_r][i]);
///消元
for(int i=row+1; i<equ; i++)
if(a[i][col])
for(int j=col; j<var+1; j++)
a[i][j] ^= a[row][j];
}
for(int i=row; i<equ; i++)
if(a[i][col])
return -1;///无解
///保证对角线主元非 0
for(int i=0; i<equ; i++)
{
if(!a[i][i])
{
int j;
for(j=i+1; j<var; j++)
if(a[i][j])
break;
if(j == var)
break;
for(int k=0; k<equ; k++)
swap(a[k][i], a[k][j]);
}
}
if(row < var)
return var - row;///自由变元的个数
///回代,得到解集
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 Debug()
{
puts("");
cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
for(int i=0; i<equ; i++)
{
for(int j=0; j<var+1; j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
puts("");
}
void Init()
{
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
for(int i=0; i<equ; i++)
{
a[i][i] = 1;
int tmp = i;
while(tmp-4 >= 0)
{
a[tmp-4][i] = 1;
tmp -= 4;
}
tmp = i;
while(tmp+4 < 16)
{
a[tmp+4][i] = 1;
tmp += 4;
}
int ta = i % 4, tb = i / 4;
tmp = i;
for(int j=0; j<ta; j++)
{
tmp--;
a[tmp][i] = 1;
}
tmp = i;
for(int j=ta; j<3; j++)
{
tmp++;
a[tmp][i] = 1;
}
}
}
char str[MAXN][MAXN];
int main()
{
equ = var = 16;
/**Init();
Gauss();
Debug();**/
while(cin>>str[0])
{
for(int i=1; i<4; i++)
cin>>str[i];
Init();
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(str[i][j] == '+')
a[i*4+j][var] = 1;
else
a[i*4+j][var] = 0;
int tmp = Gauss(), sum = 0;
for(int i=0; i<var; i++)
sum += x[i];
cout<<sum<<endl;
for(int i=0; i<var; i++)
if(x[i])
cout<<i/4+1<<" "<<i%4+1<<endl;
}
return 0;
}
第二种方法:
首先我们通过系数矩阵,先进行消元发现只有唯一解,所以根据求逆的那个公式,做出来了,这就是求逆的过程,也已经讲过了。
My Code:
/**
2016 - 09 - 09 晚上
Author: ITAK
Motto:
今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 400;
const int MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
int equ, var;///equ个方程 var个变量
int a[MAXN][MAXN];///增广矩阵
int c[MAXN][MAXN];
void Gauss()
{
int row = 0;
for(int col=0; col<var; col++)///代表列,主元的位置
{
int k = col;///k 代表行,从对角线的行开始
for(; k<equ; k++)
if(a[k][col])///找到当前列不为 0 的数作为主元
break;
if(k == equ)///含有自由变量,row表示开始自由变量的行数
{
row = col;
break;
}
for(int i=0; i<var+1; i++)///交换行
swap(a[col][i], a[k][i]);
for(int i=0; i<equ; i++)///开始消元,i 代表行
{
if(col!=i && a[i][col])///不是主元行,且要消元的行必须是1
for(int j=0; j<var+1; j++)///j 代表列
a[i][j] ^= a[col][j];
}
}
for(int i=0; i<16; i++)
for(int j=0; j<16; j++)
c[i][j] = a[i][j+16];
}
void Debug()
{
puts("");
cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
for(int i=0; i<equ; i++)
{
for(int j=0; j<16; j++)
{
cout<<c[i][j]<<" ";
}
cout<<endl;
}
cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
puts("");
}
void Init()
{
memset(a, 0, sizeof(a));
for(int i=0; i<equ; i++)
{
a[i][i] = 1;
int tmp = i;
while(tmp-4 >= 0)
{
a[tmp-4][i] = 1;
tmp -= 4;
}
tmp = i;
while(tmp+4 < 16)
{
a[tmp+4][i] = 1;
tmp += 4;
}
int ta = i % 4, tb = i / 4;
tmp = i;
for(int j=0; j<ta; j++)
{
tmp--;
a[tmp][i] = 1;
}
tmp = i;
for(int j=ta; j<3; j++)
{
tmp++;
a[tmp][i] = 1;
}
}
for(int i=0; i<16; i++)
a[i][i+16] = 1;
}
int x[MAXN], b[MAXN];
char str[MAXN][MAXN];
int main()
{
equ = 16;
var = 32;
Init();
Gauss();
///Debug();
while(cin>>str[0])
{
for(int i=1; i<4; i++)
cin>>str[i];
///!!!注意初始化
memset(x, 0, sizeof(x));
memset(b, 0, sizeof(b));
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(str[i][j] == '+')
b[i*4+j] = 1;
for(int i=0; i<16; i++)
for(int j=0; j<16; j++)
x[i] ^= (c[i][j]*b[j]);
int sum = 0;
for(int i=0; i<16; i++)
sum += x[i];
cout<<sum<<endl;
for(int i=0; i<16; i++)
if(x[i])
cout<<i/4+1<<" "<<i%4+1<<endl;
}
return 0;
}
第三种方法:
直接打表,直接通过高斯消元得到 A−1 ,然后把 A−1 的矩阵保存在一个数组中,直接进行矩阵乘法就 OK 了
My Code:
/**
2016 - 09 - 09 晚上
Author: ITAK
Motto:
今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 400;
const int MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
int x[MAXN], b[MAXN];
char str[MAXN][MAXN];
int cc[16][16]={1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,
1 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,
1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,
1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,
1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,
0 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,
0 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,
0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,
1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,
0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,
0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,
0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,
1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,
0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,
0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,
0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,
};
int main()
{
/**equ = 16;
var = 32;
Init();
Gauss();
Debug();*/
while(cin>>str[0])
{
for(int i=1; i<4; i++)
cin>>str[i];
///!!!注意初始化
memset(x, 0, sizeof(x));
memset(b, 0, sizeof(b));
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(str[i][j] == '+')
b[i*4+j] = 1;
for(int i=0; i<16; i++)
for(int j=0; j<16; j++)
x[i] ^= (cc[i][j]*b[j]);
int sum = 0;
for(int i=0; i<16; i++)
sum += x[i];
cout<<sum<<endl;
for(int i=0; i<16; i++)
if(x[i])
cout<<i/4+1<<" "<<i%4+1<<endl;
}
return 0;
}