在C

时间:2015-09-04 07:22:18

标签: c recursion

#include <stdio.h>
#include <stdlib.h>

int chessboard[8][8];
int indicator, x, i, j, b, checksum, testerint, temp, row, column;
int rescounter, resstarter;

void togglecolumn(int columnumber) {
    //
    for (j = 0; j < 8; j++) {
        //
        chessboard[j][columnumber] = toggleint(chessboard[j][columnumber]);
    }
}

void togglerow(int rownumber) {
    //
    for (j = 0; j < 8; j++) {
        //
        chessboard[rownumber][j] = toggleint(chessboard[rownumber][j]);
    }
}

void fulltoggle(int i, int j) {
    //
    togglerow(i);
    togglecolumn(j);
    chessboard[i][j] = toggleint(chessboard[i][j]);

}

int toggleint(int a) {
    //
    if (a == 0) {
        b = 1;
    }
    if (a == 1) {
        b = 0;
    }
    return b;
}

void fillchessboard() {
    x = 1;
    //
    for (i = 0; i < 8; i++) {
        x = toggleint(x);
        for (j = 0; j < 8; j++) {
            //
            chessboard[i][j] = x;
            x = toggleint(x);
        }
    }
}

void showchessboard() {
    //
    printf("------------------- \n \n");

    for (i = 0; i < 8; i++) {
        //
        for (j = 0; j < 8; j++) {
            //
            if (j == 7) {
                //if end of the row
                printf("%d \n", chessboard[i][j]);
            } else {
                //
                printf("%d  ", chessboard[i][j]);
            }
        }

    }
    printf("\n \n");
    printf("------------------- \n \n");

}

int checkboard() {
    checksum = 0;

    for (i = 0; i < 8; i++) {
        //
        for (j = 0; j < 8; j++) {
            //
            if (chessboard[i][j] == 1) {
                //
                return 1;
            }
        }
    }

    return 0;
}

void rowcolindicator(int i) {
    //
    if (i % 8 == 0) {
        column = 7;
        row = i / 8 - 1;
    } else {
        row = i / 8;
        column = i % 8 - 1;
    }
}

// for proper operation i should be chosen 0

int recurfuntion(int i, int stepcounter) {
    if (stepcounter != 0) {
        stepcounter--;
        temp = i;
        for (i = temp + 1; i < 65; i++) {
            //do row and column for 
            rowcolindicator(i);
            fulltoggle(row, column);
            recurfuntion(i, stepcounter);
        }
        if (i == 65) {
            i = temp++;
            rowcolindicator(temp);
            fulltoggle(row, column);
            stepcounter++;
        }
    } else {
        //
        temp = i;
        for (i = temp + 1; i < 65; i++) {
            //do row and column for i code and return iteration number if board turns all right
            rowcolindicator(i);
            fulltoggle(row, column);

            if (checkboard() == 0) {
                //
                showchessboard();
                return 1;
            } else {
                //
                fulltoggle(row, column);
            }
        }
        if (i == 65) {
            i = temp++;
            rowcolindicator(temp);
            fulltoggle(row, column);
            stepcounter++;
            //showchessboard();
        }
    }
}

int main(int argc, char *argv[]) {

    fillchessboard();
    showchessboard();
    indicator = checkboard();
    printf("indicator is %d \n", indicator);

    for (rescounter = 0; rescounter < 1000; rescounter++) {
        fillchessboard();
        printf("iiteration number: %d \n", rescounter);
        if (recurfuntion(0, rescounter) == 1) {
            printf("iteration number is %d so is the answer :) \n", rescounter);
        }
    }

    system("PAUSE");

    return 0;
}

我正在尝试解决此问题:&#34;您在计算机屏幕上有一个8x8表格,所有正方形颜色为白色。在每个步骤中,您将选择任意方块,因此同一行和列上的所有方块(包括所选方块本身)将切换其颜色(白色变为黑色,黑色变为白色)。 获得标准彩色棋盘所需的最小步数是多少?&#34;

为此,我将棋盘分成64块(8x8)并计算这个64s簇的所有组合,从1到64.(我知道答案在1到64之间)。

我的方法是从最后(棋盘)开始到全白。所以我用一个(黑色)和零(白色)填充板,并在功能fillchessboard()中成功构建棋盘。我可以完美地切换行和列我选择的初始方块。

如果所有电路板都是白色,则检查方法是检查板()。如果所有板都是白色,则此函数将指示器返回为0,否则返回1。我从小组合开始到更大的组合,并在每个步骤中检查电路板。因此,当指标第一次返回为0时,它将是最小的迭代数,使董事会全白,并成为问题的答案。

到目前为止,我的代码工作正常,并且在10个小时内它可以升级到第10次迭代。然而,它将花费越来越多的时间,因此第11次迭代将花费大约10个小时,第12次迭代将花费20个小时等等...我的问题是,这些指令是否有任何方法更快速有效?我等不到一个星期来解决这个问题。我很感激任何帮助。谢谢!

2 个答案:

答案 0 :(得分:7)

首先让我们做一些命名:

  • c_{i,j}是行i和列j交叉处的单元格。
  • cross_{i,j}是集合:{​​{1}}。它是行{ c_{r,c} / r=i or c=j }联合列i中所有单元格的交叉。它包含奇数数量的单元格。
  • j是一个函数,如果odd(cross_{i,j})中存在偶数个黑色单元,则返回0;如果存在奇数个黑色单元,则返回1。

让我们考虑选择单元格cross_{i,j}

的效果
  1. 它会在c_{i,j}中切换奇数个单元格,因此会切换cross_{i,j}的值。
  2. 对于所有其他“十字架”,受影响的细胞数量将是均匀的,因此任何odd(cross_{i,j}) odd(cross_{k,l})值都不会改变
  3. 第2点的原因是(k,l) \neq (i,j)cross_{k,l}的交叉只有3个案例:

    1. 这是一整行,有一定数量的单元格。
    2. 这是一个包含偶数单元格的整列。
    3. cross_{i,j}为一个单元格,列k为一个单元格。
    4. 因此,对于每种可能性,偶数个单元格会改变颜色,因此l的值不会改变。

      因此,切换odd(cross_{k,l})值的唯一方法是选择odd(cross_{i,j})

      在比赛结束时,有32个十字架,它们已经切换了价值。因此,任何解决方案的最小步骤数为32。

      现在,之前的推理还表明,选择感兴趣的32个细胞将产生最终的棋盘状态。

      所以这是一个最小的解决方案。

      对不起,这里有没有编程:)

答案 1 :(得分:2)

这不是一个解决方案,但有些指针应该有助于降低问题的复杂性(但不是难度)。

国际象棋棋盘有2 ^ 64种不同的状态。

国际象棋棋盘有一些属性可以帮助你减少有趣状态的数量。

每次移动翻转15个瓦片(奇数)。由于您以偶数个白色瓷砖开始和结束,因此您知道移动的总数是均匀的。

此外,您执行移动的顺序无关紧要。选择相同的方块两次可以反转前一次翻转。所以我们只需要弄清楚要选择的64个区块中的哪一个。

因此我们可以使用64位来表示解决方案,每个位代表一个选定的磁贴或一个未选择的磁贴。我们可以使用64位长的时间来存储可能的解决方案。

此外,如果您使用64位长来存储电路板的状态,则每一步都是一个XOR,其数字会翻转右边的15个磁贴(设置了这15个磁贴的数字)。

棋盘是对称的。如果你转动它或镜像它并不重要。国家是一样的。这进一步降低了复杂性,因为它证明如果X是解决方案,那么X的补充也是一种解决方案。因此,如果没有找到选择32件的解决方案,则不存在解决方案。

我的直觉(或者更确切地说是对称性)表明解决方案(如果存在的话)应该是8的倍数并且是8,16或32,其中16是最可能的。但是,我没有证据证明这一点。我应该很容易证明在8个动作中没有解决方案(并且你已经通过使用蛮力证明了这一点 - 只要你的程序是正确的。)