【问题标题】:Recursive Method For Checking All Possible Values (C)检查所有可能值的递归方法 (C)
【发布时间】:2014-12-05 20:22:05
【问题描述】:

我正在编写一个程序,它读取一个整数值 (n),并创建一个具有这些维度 (nXn) 的国际象棋表。然后我必须看看是否有一种方法可以将 n 个皇后放在这个棋盘上,这样它们就不会互相攻击(对于那些不熟悉国际象棋的人,皇后可以攻击同一列中的任何棋子或像他们一样划船,以及任何位于穿过女王的对角线上的棋子)。这些值存储在一个数组 (int board[n]) 中,最初设置为全 -1。 board[0] 中的值将对应于第 0 列中的皇后所在的行。最初,所有值都设置为-1,这意味着该行中没有一块。

我试图找到一种方法,通过一种方法检查是否可以传递所有可能的坐标集(基本上是长度为 n 的所有可能数组,其值可以在 0 和 n-1 之间)这是一种有效的布局方式,如果有一个有效的布局,它必须将该数组传递给一个可视化它的方法,如下所示:

* * Q *
Q * * *
* * * Q
* Q * *

检查和输出的方法已经设置好并且可以工作了,我只需要弄清楚如何生成存储该坐标的数组的所有可能排列。

编辑: 以下是目前的代码(12 月 6 日下午 2 点更新):

#include <stdio.h>
#include <stdlib.h>
int permutations (int board[],int n, int counter, int index);
int check (int board[], int n);
int printout (int board[], int n, int isValid);
int main() {
  int n, board[n];
  while (1==scanf("%d", &n) && n > 0) {
      int board[] = {-1};
      int isValid = permutations(board,n, 0, 0); 
      printout(board, n, isValid);
}
  return 0;
}
int permutations(int board[],int n, int counter, int index){
board[index] = counter;
int max = n-1;
if ((check(board, n) == 1) && (index == max)){
return 1;
}
if (check(board, n) == 1){
permutations(board, n, 0, ++index);
}
else if (check(board, n) == 0){
counter++;
}
if (counter == n){
return 0;
}  
}
int check(int board[], int n){
int i,j;
int isValid = 1;
for (i=0; i<n && isValid; ++i) {
      if (board[i]==-1) continue;
      for (j=i+1; j<n && isValid; ++j) {
    if (board[j]==-1) continue;
    if ( board[i] == board[j] ||
             board[i]-board[j] == i-j ||
             board[i]-board[j] == j-i )
      isValid = 0;
      }
    }
return isValid;}
int printout(int board[], int n, int isValid){
int i,j;
    putchar('\n');
    for (i=n-1; i>=0; --i) {
      for (j=0; j<n; ++j) {
    if (j>0) putchar(' ');
    putchar( board[j]==i ? 'Q' : '.' );
      }
      putchar('\n');
    }
    puts( isValid ? "valid configuration" : "invalid configuration" );
    return 0;
    }

【问题讨论】:

  • 从第一行开始。将女王放置在第一个单元格上,并将女王可以移动到的所有单元格标记为“被攻击”。然后移动到下一行,在没有被攻击的单元格上放置一个女王。等等等等。然后看看它是否在该行的不同列上与女王一起工作。你想要实际的代码吗?
  • 那将非常有帮助。我对 C 很陌生
  • 听起来像是一道作业题。如果你表明你已经做了一些研究,我很乐意提供帮助。但您似乎只是希望有人为您完成工作。
  • 如果您尝试这样做会更有帮助,然后发布代码以防遇到困难,以便获得帮助。
  • 我只是坚持下去。我尝试使用嵌套的 for 循环无济于事,现在我正在尝试递归。该问题基于之前的作业,该作业检查了该板是否有效,但现在我必须找到一种方法来找到使其有效的值。

标签: c arrays recursion


【解决方案1】:

作业提示(递归):

从一个空板开始并调用您的递归例程。遍历棋盘,试图在上面放一个皇后。如果它被攻击然后继续。否则叫你自己和董事会(现在多了一个女王)。遍历棋盘,试图在上面放一个皇后。如果它被攻击然后继续。否则叫你自己...

如果你已经达到 6 个皇后,返回“success”并展开递归。

如果您在任何时候都无法在棋盘上放置另一个皇后,请返回“失败”,移除皇后并从您调用自己的位置继续迭代。

这是一种“蛮力”方法。

【讨论】:

  • 好的,我会发布我更新的代码。我尝试实现它,但它一直默认为 true。
【解决方案2】:

此代码有效(这是您的作业):

int checkBoard(int board[8][8]);
int putQueens(int board[8][8], int nQueens);
void printBoard(int board[8][8]);

int eightQueens(void)
{
    int board[8][8];
    memset(board, 0, sizeof(int)*64);
    if (putQueens(board, 0)) {
        printBoard(board);
        return (1);
    }
    return(0);
}
int putQueens(int board[8][8], int nQueens)
{
    int i, j;
    for (i=0; i<8; i++) {
        for (j=0; j<8; j++) {
            if (board[i][j]==0) {
                board[i][j]= 1;
                if (checkBoard(board)) {
                    if (nQueens==7) return(1);
                    if (putQueens(board, nQueens+1)) return(1);
                }
                board[i][j]= 0;
            }
        }
    }
    return(0);
}
int checkBoard(int board[8][8])
{
    int i, j;
    for (i=0; i<8; i++) {
        for (j=0; j<8; j++) {
            if (board[i][j]) {
                int ii, jj;
                for (ii=i+1; ii<8; ii++) {
                    if (board[ii][j]) return(0);
                }
                for (jj=j+1; jj<8; jj++) {
                    if (board[i][jj]) return(0);
                }
                for (ii=i+1, jj=j+1; ii<8 && jj<8; ii++, jj++) {
                    if (board[ii][jj]) return(0);
                }
                for (ii=i-1, jj=j-1; ii>0 && jj>0; ii--, jj--) {
                    if (board[ii][jj]) return(0);
                }
                for (ii=i-1, jj=j+1; ii>0 && jj<8; ii--, jj++) {
                    if (board[ii][jj]) return(0);
                }
                for (ii=i+1, jj=j-1; ii<8 && jj>0; ii++, jj--) {
                    if (board[ii][jj]) return(0);
                }
            }
        }
    }
    return (1);
}

我只是对 checkBoard 不满意;它可以变得更优雅。 (你的作业)。

所以你已经学会了:请发表评论,解释你的代码哪里出了问题,以及你从上面的代码中学到了什么。

【讨论】:

    【解决方案3】:

    main() 中的边际错误:在输入 n 之前不要定义可变长度数组 board[n]。 现在进入算法:对于分配的任务(将nquenes 放在板上),生成包含少于nqueens 的布局是没有意义的。所以用一些排列来初始化board,这些排列可能会被重新排列成一个有效的布局;我在下面选择了{ 0, 1, 2 .. n-1 }。我重写了函数permutations(),以生成数组的所有可能排列board[]如果有一个有效的布局,...将该数组传递给一个方法可视化它(你原来的printout())。此外,该函数会为有效布局增加一个计数器 - 我发现计数如何随着 n 的不同值而变化很有趣。

    int n, counter; // counter: counts valid layouts found
    
    void permutations(int board[], int j)
    {   // generate all possible permutations of board[0..j-1]
        int i = --j;
        if (i <= 0)
        {   // arrived at one permutation - check it, and print if valid
            if (check(board, n)) ++counter, printout(board, n, 1);
            return;
        }
    
        permutations(board, i);
        while (i--)
        {
            int k, x;
            for (k = j; k > i; --k)
                if (board[i] == board[k]) break;
            if (k > i) continue;
    
            x = board[i], board[i] = board[j], board[j] = x;
            permutations(board, j);
            x = board[i], board[i] = board[j], board[j] = x;
        }
    }
    
    int main()
    {
        while (1==scanf("%d", &n) && n > 0)
        {
            int board[n], i;
            for (i = 0; i < n; ++i) board[i] = i;
            counter = 0, permutations(board, n); 
            printf("%d valid configurations\n", counter);
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2020-04-08
      • 1970-01-01
      • 2020-11-02
      • 2013-03-14
      • 1970-01-01
      相关资源
      最近更新 更多