213 lines
5.5 KiB
C++
213 lines
5.5 KiB
C++
#include <bits/stdc++.h>
|
|
|
|
#define FOR(i, n) for(lli i = 0; i < (lli)(n); ++i)
|
|
|
|
#define X(A) get<0>(A)
|
|
#define Y(A) get<1>(A)
|
|
#define Z(A) get<2>(A)
|
|
#define W(A) get<3>(A)
|
|
|
|
#define mt make_tuple
|
|
#define mp make_pair
|
|
#define pb push_back
|
|
|
|
#define fst first
|
|
#define snd second
|
|
|
|
|
|
using namespace std;
|
|
using lli = long long int;
|
|
using ll = long long int;
|
|
|
|
using pii = tuple<lli, lli>;
|
|
using piii = tuple<lli, lli, lli>;
|
|
using vi = vector<lli>;
|
|
using vii = vector<pii>;
|
|
using viii = vector<piii>;
|
|
using vvi = vector<vi>;
|
|
using vvii = vector<vii>;
|
|
using vviii = vector<viii>;
|
|
using vb = vector<bool>;
|
|
using vvb = vector<vb>;
|
|
|
|
|
|
template<int N> // N = dimension
|
|
struct gauss {
|
|
bitset<N> A[N]; // upper diagonal matrix (free family)
|
|
int V[N]; int nv=0; // identify the columns
|
|
bitset<N> B[N]; // how elements of A are generated ?
|
|
|
|
gauss() { reset(); }
|
|
void reset() {
|
|
// memset(this,0,sizeof(gauss<N>)); should work as well
|
|
FOR(i,N) A[i].reset();
|
|
nv=0;
|
|
FOR(i,N) B[i].reset();
|
|
}
|
|
|
|
// add a matrix column (a vector in the free family)
|
|
void add(int id, bitset<N> x) {
|
|
if(nv == N) return;
|
|
bitset<N> y; y[nv]=1;
|
|
FOR(i,N) if(x[i]) {
|
|
if(A[i][i]) { x ^= A[i]; y ^= B[i]; }
|
|
else { A[i] = x; V[nv++] = id; B[i] = y; return; }
|
|
}
|
|
}
|
|
|
|
// reach a vector x
|
|
// returns true when possible, false otherwise
|
|
// y contains the vectors of V used
|
|
bool solve(bitset<N> x, bitset<N> &y){
|
|
y.reset();
|
|
FOR(i,N) if(x[i]&&A[i][i]) {
|
|
x ^= A[i];
|
|
y ^= B[i];
|
|
}
|
|
if(x.any()) return false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// example usage : solve a linear system in Z/2Z
|
|
// M is a matrix (list of columns)
|
|
// X is a vector
|
|
// solves M Y = X
|
|
// returns in Y the indices of columns of M with xor X
|
|
const int DIM=2500;
|
|
bool solve(vector<bitset<DIM> > M, bitset<DIM> X, vi &Y) {
|
|
gauss<DIM> G;
|
|
FOR(i,M.size()) {
|
|
G.add(i, M[i]);
|
|
}
|
|
bitset<DIM> y;
|
|
if (!G.solve(X, y))
|
|
return false;
|
|
for (int i = 0; i < DIM; ++i)
|
|
if (y[i])
|
|
Y.pb(G.V[i]);
|
|
return true;
|
|
}
|
|
|
|
|
|
// Inspire de https://github.com/stjepang/snippets/blob/master/gauss.cpp
|
|
// Elimination de Gauss
|
|
// Resout un systeme d'equations lineaires
|
|
// Complexite : O(nb_lins * nb_cols^2)
|
|
// Si le systeme a au moins une solution, value contiendra une solution possible
|
|
const int MAX_NB_COLS = 2500;
|
|
const double eps = 1e-8;
|
|
|
|
struct Gauss {
|
|
// posnz[i] = -1 si la i-eme composante est libre
|
|
int posnz[MAX_NB_COLS];
|
|
// value[i] = la valeur de X(i) verifiant l'equation ci-dessous
|
|
int value[MAX_NB_COLS];
|
|
// vrai ssi. le systeme a >= 1 solution
|
|
bool has_solution;
|
|
|
|
// mat[0 .. nb_lins-1][0 .. nb_cols-1] * X = mat[0 .. nb_lins-1][nb_cols]
|
|
Gauss(int mat[][MAX_NB_COLS + 1], int nb_lins, int nb_cols) {
|
|
fill(posnz, posnz + nb_cols, -1);
|
|
|
|
|
|
for (int i = 0; i < nb_lins; ++i, puts(""))
|
|
for (int j = 0; j < nb_cols; ++j)
|
|
printf("%d ", mat[i][j]);
|
|
int posnz_cur = 0;
|
|
for (int col = 0; col < nb_cols; ++col) {
|
|
int max_lin = posnz_cur;
|
|
|
|
for (int lin = max_lin + 1; lin < nb_lins; ++lin)
|
|
if (fabs(mat[lin][col]) > fabs(mat[max_lin][col]))
|
|
max_lin = lin;
|
|
|
|
// La colonne est nulle
|
|
// Condition de la forme == 0 si on est dans les entiers
|
|
if (mat[max_lin][col] == 0) continue;
|
|
|
|
for (int i = 0; i <= nb_cols; ++i)
|
|
swap(mat[max_lin][i], mat[posnz_cur][i]);
|
|
|
|
for (int lin = 0; lin < nb_lins; ++lin) {
|
|
if (lin == posnz_cur) continue;
|
|
// Pour Gauss modulaire : remplacer par l'inverse de mat[posnz_cur][col]
|
|
int factor = mat[lin][col] * (1 ^ mat[posnz_cur][col]);
|
|
for (int i = 0; i <= nb_cols; ++i) {
|
|
mat[lin][i] -= factor * mat[posnz_cur][i];
|
|
mat[lin][i] %= 2;
|
|
mat[lin][i] += 2;
|
|
mat[lin][i] %= 2;
|
|
}
|
|
// Gauss mod : rajouter le modulo
|
|
}
|
|
|
|
posnz[col] = posnz_cur++;
|
|
}
|
|
|
|
// Genere une solution valide
|
|
for (int col = 0; col < nb_cols; ++col) {
|
|
if (posnz[col] != -1)
|
|
value[col] = mat[posnz[col]][nb_cols] * (1 ^ mat[posnz[col]][col]);
|
|
// Gauss mod
|
|
else
|
|
value[col] = 0;
|
|
}
|
|
|
|
for (int i = 0; i < nb_lins; ++i, puts(""))
|
|
for (int j = 0; j < nb_cols; ++j)
|
|
printf("%d ", mat[i][j]);
|
|
|
|
// Verifie que la solution generee est valide
|
|
has_solution = true;
|
|
for (int lin = 0; lin < nb_lins; ++lin) {
|
|
int sum = 0;
|
|
for (int col = 0; col < nb_cols; ++col) {
|
|
sum += mat[lin][col] * value[col]; // Gauss mod
|
|
sum %= 2;
|
|
}
|
|
if (sum - mat[lin][nb_cols] != 0) // Gauss mod
|
|
has_solution = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
const int MAXN = 50, MAXM = 50;
|
|
int grid[MAXN][MAXM];
|
|
int mat[MAXN * MAXM][MAXN * MAXM + 1];
|
|
int N, M;
|
|
|
|
int linof(int i) { return i / M; }
|
|
int colof(int i) { return i % M; }
|
|
|
|
int main() {
|
|
scanf("%d%d", &N, &M);
|
|
for (int i = 0; i < N; ++i)
|
|
for (int j = 0; j < M; ++j) {
|
|
char c;
|
|
scanf(" %c", &c);
|
|
grid[i][j] = c == 'W';
|
|
}
|
|
vector<bitset<DIM>> mat(DIM);
|
|
bitset<DIM> X;
|
|
for (int i = 0; i < N * M; ++i)
|
|
for (int j = 0; j < N * M; ++j)
|
|
mat[i][j] = linof(i) == linof(j) || colof(i) == colof(j);
|
|
for (int i = 0; i < N * M; ++i)
|
|
X[i] = grid[linof(i)][colof(i)] ^ 1;
|
|
/*
|
|
for (int i = 0; i < N * M; ++i)
|
|
mat[i][N * M] = grid[linof(i)][colof(i)] ^ 1;
|
|
*/
|
|
vi Y;
|
|
if (solve(mat, X, Y)) {
|
|
puts("Yes");
|
|
printf("%d\n", (int)Y.size());
|
|
for (int x: Y)
|
|
printf("%d %d\n", linof(x) + 1, colof(x) + 1);
|
|
} else
|
|
puts("No");
|
|
return 0;
|
|
}
|