C++ 用贪心方法(回溯法)寻找熄灯游戏的解决方案
我正在尝试用回溯法来寻找熄灯游戏的解决方案。我无法理解这个过程的算法。我的方法是枚举从0到2n2-1的所有整数,并将每个整数转换为一个具有n*n位的二进制数。然后,将其分离为n2个二进制数字(0表示熄灭,1表示点亮),并将其分配到n×n网格中,例如: 我编写了以下代码:-C++ 用贪心方法(回溯法)寻找熄灯游戏的解决方案,c++,algorithm,C++,Algorithm,我正在尝试用回溯法来寻找熄灯游戏的解决方案。我无法理解这个过程的算法。我的方法是枚举从0到2n2-1的所有整数,并将每个整数转换为一个具有n*n位的二进制数。然后,将其分离为n2个二进制数字(0表示熄灭,1表示点亮),并将其分配到n×n网格中,例如: 我编写了以下代码:- void find_solution(int dest[][MAX_SIZE], int size) { int y = pow(size,size); int remainder; for
void find_solution(int dest[][MAX_SIZE], int size) {
int y = pow(size,size);
int remainder;
for (int x = 0; x<pow(2,y); x++){
int i = 1;
int binary_number = 0;
int n = x;
while (n!=0) {
remainder = n%2;
n/=2;
binary_number += remainder*i;
i *= 10;
}
int binary_number_digits[size][size];
for (int k = 0; k<size; k++) {
for (int l = 0; l<size; l++) {
binary_number_digits[k][l] = binary_number%10;
binary_number/=10;
}
}
int count = 0;
for (int i = 0; i<size; i++) {
for (int j = 0; j<size; j++) {
if (binary_number_digits[i][j] == dest[i][j]) {
count++;
}
if (count <= 4 && count > 0) {
if (binary_number_digits[i][j] == 1) {
cout << i << j;
}
}
}
}
}
}
void find_解决方案(int dest[][MAX_SIZE],int SIZE){
int y=功率(大小,大小);
整数余数;
对于(int x=0;x而言,需要进行以下观察(如表中所列):
- 在解决方案中,每个灯最多只能按一次。这是因为按一个灯奇数次等于按一次,按一个灯偶数次等于不按
- 灯光按下的顺序无关紧要。这与前一点相同:切换灯光会改变其相邻灯光,但对于相邻灯光的最终结果,只有在其被更改偶数或奇数次时才有意义
由此我们可以得出结论,我们可以将一个解决方案表示为与电路板大小相同的0-1矩阵,其中1表示在解决方案中,应按下该位置的灯光。然后,蛮力算法检查所有nxn 0-1矩阵,以查看这些矩阵中是否有解算初始电路板
在您的实现中,您执行第一步(生成表示按下指示灯方式的所有nxn 0-1矩阵)。您缺少检查哪一步解决了电路板问题
我将通过使用来稍微简化二进制数的处理
(下面的代码还需要C++17来实现。)
#包括
#包括
#包括
#包括
模板
班级董事会{
公众:
void print()常量{
对于(size_t i=0;i0){
复制.data.flip(偏移量-N);
}
如果(y STD::这是你正在谈论的熄灯游戏吗?嗨,如果你能提供一些测试的证据,比如输入/输出/预期结果/实际结果,它可能是有用的。你可以考虑把代码分成更小的块,这样你就可以确定哪个部分不起作用。@ ATTY是正确的。但是,我正在实现这个G。ame基本上是2*2、3*3和4*4网格。我不明白你的算法背后的想法。你基本上是在列举所有可能的电路板状态。这如何帮助你确定你必须按哪个顺序按下灯才能将它们全部关闭?你没有解释这个暴力算法有什么问题(不是贪婪的,也不是回溯)。它可能很慢,但是这个算法应该提供答案,除非实现有问题。
#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;
}