Требуются следующие наблюдения (как указано в Wiki ):
В решении каждый источник света должен нажиматься не более одного раза. Это связано с тем, что нажатие на источник света нечетное количество раз эквивалентно нажатию на него один раз, а нажатие на источник света четное число раз эквивалентно тому, что он не нажат.
Порядок, в котором огни нажаты не имеет значения. Это следует из предыдущего пункта: переключение источника света изменяет его соседей, но для конечного результата соседа это имеет значение, только если оно было изменено четное или нечетное количество раз.
С Из этого можно сделать вывод, что мы можем представить решение в виде матрицы 0-1 того же размера, что и доска, где 1 означает, что в решении должен быть нажат свет в этой позиции. Алгоритм перебора должен затем проверить все nxn 0-1 матрицы, чтобы увидеть, решает ли какой-либо из них исходную плату.
В вашей реализации вы делаете первый шаг (генерируете все nxn 0-1 матрицы, которые представлять способы нажатия ламп). Вы пропускаете этап проверки того, какие из них решают плату.
Я бы немного упростил обработку двоичных чисел, используя std :: bitset .
(следующее Код также требует C ++ 17 для std :: необязательно .)
#include <bitset>
#include <iostream>
#include <optional>
#include <random>
template <size_t N>
class board_t {
public:
void print() const {
for (size_t i = 0; i < data.size(); i++) {
std::cout << data[i];
if (i % N == N - 1) {
std::cout << std::endl;
}
}
}
void randomize() {
std::random_device device;
std::default_random_engine generator{device()};
std::bernoulli_distribution bernoulli(0.5);
for (size_t i = 0; i < data.size(); i++) {
data[i] = bernoulli(generator);
}
}
/**
* Brute-force all possible ways of pressing the lights.
*/
std::optional<board_t<N>> solve() const {
board_t<N> press{};
do {
board_t<N> applied{this->apply(press)};
if (applied.data.none()) {
return press;
}
press.increment();
/**
* Aborts when incrementing press overflows back to the initial
* solution of not pressing any lamp.
*/
} while (press.data.any());
/**
* Return empty std::optional when no solution was found.
*/
return {};
}
private:
/**
* Indicates which lights are on.
*/
std::bitset<N * N> data;
/**
* Interpret the board as a N*N bit binary number and increment it by one.
*/
void increment() {
for (size_t i = 0; i < data.size(); i++) {
if (data[i]) {
data[i] = false;
} else {
data[i] = true;
break;
}
}
}
/**
* Press each light indicated by press.
*/
board_t<N> apply(const board_t<N>& press) const {
board_t<N> copy{*this};
for (size_t y = 0; y < N; y++) {
for (size_t x = 0; x < N; x++) {
size_t offset = x + y * N;
if (press.data[offset]) {
copy.data.flip(offset);
/**
* Check neighbors.
*/
if (x > 0) {
copy.data.flip(offset - 1);
}
if (x < N - 1) {
copy.data.flip(offset + 1);
}
if (y > 0) {
copy.data.flip(offset - N);
}
if (y < N - 1) {
copy.data.flip(offset + N);
}
}
}
}
return copy;
}
};
int main(void) {
constexpr size_t N = 3;
board_t<N> board{};
board.randomize();
board.print();
auto solution{board.solve()};
if (solution) {
std::cout << "Solution:" << std::endl;
solution->print();
} else {
std::cout << "No solution!" << std::endl;
}
return 0;
}