N皇后放置算法

时间:2012-07-13 18:47:44

标签: c algorithm

我正在解决N皇后问题,我们需要在N X N棋盘上放置N个皇后,这样就不会有两个皇后可以相互攻击。

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

int size=8;
char arr[8][8];
int i,j;

void initializeBoard()
{
  for(i=0;i<size;i++)
  {
    for(j=0;j<size;j++)
    {
        arr[i][j]='.';
    }
  }
}

void printArray()
{

  for(i=0;i<size;i++)
  {

    for(j=0;j<size;j++)
    {
        printf("%c\t",arr[i][j]);
    }

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

void placeQueen(int i,int j)
{
  arr[i][j]='Q';
}

int isAvailable(int i,int j)
{
   int m,n,flag;

   for(m=0;m<i;m++)
   {
      for(n=0;n<size;n++)
      {
        int k=abs(i-m);
        int l=abs(j-n);

        if(arr[m][j]!='Q' && arr[k][l]!='Q')
        {
            flag=1;
        }

        else
        {
            flag=0;
            break;
        }
    }
}
return flag;

}


int main(void)
{
    initializeBoard();

    for(i=0;i<size;i++)
    {
        for(j=0;j<size;j++)
        {
            if(isAvailable(i,j)==1)
            {
                // means that particular position is available
                // and so we place the queen there

                placeQueen(i,j);
                break;
            }
        }
    }

    printArray();
    return 0;
}

我认为问题出在isAvailable()方法上。但是,我无法找到错误。请帮我识别一下。

我采取的方法是否涉及回溯?如果没有,请提供相同的解释

4 个答案:

答案 0 :(得分:1)

之前完成此问题,并非所有展示位置都允许有效解决问题。

您的解决方案涉及始终将女王放置在始终可用的位置(0,0)。

当你经历一切并且找不到任何东西时,你将需要涉及回溯,或者你需要依赖一个解决方案,将所有女王随机放置并检查解决方案(这种方法实际上比你会想,但同时,随机因此在一般情况下非常低效)

潜在的伪解决方案:

while(!AllQueensPlaced){
    for(going through the array ){
        if(isAvailable())
        {
            placeQueen();
            lastQueenPlaced = some logical location of last queen;
        }
    }
    if(!AllQueensPlaced)
    {
         backtrack(lastQueenPlaced);
    }
}

你的回溯方法应该将lastQueenPlaced标记为脏并再次遍历数组寻找新位置,然后再次执行while循环。不要忘记在backtrack()中更改lastQueenPlaced,以防它也是lastQueenPlaced。

答案 1 :(得分:1)

您的方法不会回溯。它迭代了一些可能性,而不是全部。这个问题最好以递归的方式解决,所以我不会像你那样做。你必须为女王被其他人攻击的规则定义。您可以使用ifs和递归来再次应用规则并进行迭代。大多数回溯算法都是递归写入的。 我会给你一个答案,所以你可以根据我的答案。

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

int count = 0;
void solve(int n, int col, int *hist)
{
    int i, j;
    if (col == n) {
        printf("\nNo. %d\n-----\n", ++count);
        for (i = 0; i < n; i++, putchar('\n'))
            for (j = 0; j < n; j++)
                putchar(j == hist[i] ? 'Q' : ((i + j) & 1) ? ' ' : '.');

        return;
    }

#   define attack(i, j) (hist[j] == i || abs(hist[j] - i) == col - j)
    for (int i = 0, j = 0; i < n; i++) {
        for (j = 0; j < col && !attack(i, j); j++);
        if (j < col) continue;

        hist[col] = i;
        solve(n, col + 1, hist);
    }
}

int main(int n, char **argv)
{
    if (n <= 1 || (n = atoi(argv[1])) <= 0) n = 8;
    int hist[n];
    solve(n, 0, hist);
}

回溯的方式如下:

  1. 创建约束(规则)以检查条件是否满足。
  2. 将问题视为搜索树。搜索此树所花费的时间基于n,即电路板的大小。搜索的最佳方式是递归,因此请记住,解决的智能方法是使用递归。
  3. 在该代码中,第一组for循环只打印出来,并检查Q是否找到。
  4. # define attack(i, j) (hist[j] == i || abs(hist[j] - i) == col - j)是我的规则,断言2个皇后不互相攻击。
  5. 第二组for循环在约束规则中找到可以插入另一个女王的条件。
  6. 然后我再次调用find函数。这就是回溯的方式。
  7. 我的基本情况是2个皇后可以在棋盘上,然后我会递归检查是否可以添加另一个女王直到8。因此,2 + 1 =(1 + 1)+ 1 = 1(1 + 1)。再次应用规则,我们有3 + 1 =(2)+ 1 + 1 =(2)+(1 + 1),再次4 =(3)+ 1 + 1 =(3)+(1 + 1)
  8. 递归为你做到了。让我们一遍又一遍地应用规则。因此f(n+1) = f(n) + 1针对该案例而f(2) = 2是我的基本案例。
  9. 回溯的基础是,如果其中一个分支无法解决,您可以向上一级并搜索另一个分支,依此类推,直到所有树都被搜索出来。再次,递归是要走的路。

答案 2 :(得分:0)

使用单维数组来跟踪每行中可放置后置的列。

可以将女王受到威胁的条件定为 1)ColumnForRow [i] == ColumnForRow [j] - 它们将在同一列中 2)(ColumnForRow [i] - ColumnForRow [j])==(i-j)或    (ColumnForRow [j] - ColumnForRow [i])==(i - j) - 它们将在同一对角线上。

公共课NQueenSolver {

static int BOARD_SIZE = 15;
static int count = 0;
static int columnForRow[] = new int[BOARD_SIZE];

public static void main(String[] args) {
    PlaceQueen(0);
    System.out.println(count);
}

static boolean check(int row) {
    for (int i = 0; i < row; i++) {
        int diff = Math.abs(columnForRow[i] - columnForRow[row]);
        if (diff == 0 || diff == row - i)
            return false;
    }
    return true;
}

static void PlaceQueen(int row) {
    if (row == BOARD_SIZE) {
        printBoard();
        ++count;
        return;
    }
    for (int i = 0; i < BOARD_SIZE; i++) {
        columnForRow[row] = i;
        if (check(row)) {
            PlaceQueen(row + 1);
        }
    }
}

private static void printBoard() {
    //System.out.println(Arrays.toString(columnForRow));
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (columnForRow[i] == j)
                System.out.print("Q ");
            else
                System.out.print("* ");
        }
        System.out.println();
    }
    System.out.println();
}

}

答案 3 :(得分:0)

你的代码没有递归方法,这是在设计回溯算法时应首先考虑的问题。因此,您没有在此实施任何回溯策略。

你的函数isAvailable()在很多方面都不完整。

要检查已放置的皇后是否有单元格(行,列)受到攻击,您可以使用以下策略。

注意事项:

  1. 逐行放置女王

  2. 要将女王放在第i行,我们需要检查与放置在0到第(i-1)行的女王的冲突。

  3. 女王水平,垂直和对角线攻击。

  4. 代码(参考:Tushar Roy的讲座/代码)

    boolean isSafe = true;
    for(int queen = 0; queen<row; queen++) // Checking with already placed queens
    {
        // attack condition
        if(position[queen].column == column || position[queen].row + 
        position[queen].column == row + column || position[queen].row - 
        position[queen].column == row-column)
        {
            isSafe = false;
            break;
        }
    }
    

    希望这有帮助。