gpt4 book ai didi

c++ - 使用贪婪方法寻找熄灯游戏的解决方案(回溯)

转载 作者:行者123 更新时间:2023-12-01 14:20:22 28 4
gpt4 key购买 nike

我正在尝试使用回溯方法找到熄灯游戏的解决方案。我无法理解此过程的算法。我的方法是枚举从 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 (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;
}
}
}
}
}
}

我已将十进制数字转换为二进制数字并将其存储在一个数组中并检查它们是否与随机生成的 n*n 网格匹配。如果是 1,则打印该坐标 (x,y)。任何人都可以请帮我解决这个算法的问题。谢谢!

最佳答案

需要以下观察结果(如 Wiki 所列):

  • 在解决方案中,每个灯最多只能按下一次。这是因为按奇数次等于按一次,按偶数次等于不按。
  • 按下灯的顺序无关紧要。这是从前一点得出的:切换一盏灯会改变它的邻居,但对于邻居的最终结果,只有它被改变了偶数或奇数次才重要。

  • 由此我们可以得出结论,我们可以将解决方案表示为与电路板大小相同的 0-1 矩阵,其中 1 表示在解决方案中应该按下该位置的灯。蛮力算法然后是检查所有 nxn 0-1 矩阵,看看这些矩阵中是否有任何一个解决了初始板。

    在您的实现中,您执行了第一步(生成所有 nxn 0-1 矩阵,表示按下灯的方式)。您错过了检查其中哪些解决电路板的步骤。

    我将通过使用 std::bitset 稍微简化二进制数处理.

    (以下代码也需要 C++17 for std::optional 。)
    #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;
    }

    关于c++ - 使用贪婪方法寻找熄灯游戏的解决方案(回溯),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61073535/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com