Java:八皇后算法错误

时间:2018-05-16 16:06:55

标签: java computer-science backtracking

我在这里看到的帖子与此类似,但我的情况略有不同。

我编写了displayBoard方法,但最后一列没有返回Queen。

是因为女王的值为1并且丢掉数字吗?

它一直告诉我,我有ArrayOutOfBoundsException: -1

我知道数组计数为0但我仍然无法使其工作

public class Queens 
{
    public static final int BOARD_SIZE = 8;

    public static final int EMPTY = 0;

    public static final int QUEEN = 1;

    private int board[][];

public Queens()
{
  board = new int[BOARD_SIZE][BOARD_SIZE];
}

public void clearBoard()
{
    board = new int[BOARD_SIZE][BOARD_SIZE];
}

public void displayBoard () {
    int counter = 0;
    for (int i = 0; i < BOARD_SIZE; i++) 
    {
        for (int j = 0 ; j < BOARD_SIZE; j++) 
        {
            if (board[i][j] == QUEEN ) 
            {
                System.out.print("| X |");
                counter++;
            }
            else 
            {              
                System.out.print("| 0 |");
            }
        }
        System.out.println();
    }
}

public boolean placeQueens(int column) {

if (column >= BOARD_SIZE) {
    return true;  // base case
}
else {
  boolean queenPlaced = false;
  int row = 1;  // number of square in column

  while ( !queenPlaced && (row <= BOARD_SIZE)  )  {
    // if square can be attacked
      if (isUnderAttack(row, column)) {
      ++row;  // consider next square in column
      } // end if
      else {  // place queen and consider next column
      setQueen(row, column);
      queenPlaced = placeQueens(column+1);
      // if no queen is possible in the next column,
      if (!queenPlaced) {
          // backtrack:  remove queen placed earliers
          // and try next square in column
          removeQueen(row, column);
          ++row;
      } // end if
      } // end if
  } // end while
  return queenPlaced;
} // end if
} // end placeQueens

private void setQueen(int row, int column) {
board[row-1][column-1] = QUEEN;
} // end setQueen

private void removeQueen(int row, int column) {
   board[row-1][column-1] = EMPTY;
} // end setQueen

private boolean isUnderAttack(int row, int column) {
// check column
for (int i=0; i<row-1; i++){
    if (board[i][column-1]==1){
        return true;
    }
}
// check row
for (int i=0; i<column-1; i++) {
    if (board[row-1][i] == 1){
        return true;
    }
}

// check lower diagnal
int lower_dir_row = row-2;
int lower_dir_column = column-2;
while (lower_dir_row>=0 && lower_dir_column>=0){
        if (board[lower_dir_row][lower_dir_column]==1){
            return true;
        } else {
            lower_dir_row = lower_dir_row -1;
            lower_dir_column = lower_dir_column -1;
        }
    }


 // check upper diagnal
int upper_dir_row = row;
int upper_dir_column = column-2;
while (upper_dir_row<BOARD_SIZE && upper_dir_column>=0){
    if(board[upper_dir_row][upper_dir_column] ==1){
        return true;
    }else{
        upper_dir_row = upper_dir_row +1;
        upper_dir_column = upper_dir_column -1;
    }
}
return false;

} // end isUnderAttack

public static void main(String[] s) 
{
    Queens q = new Queens();
    q.placeQueens(0);
    q.displayBoard();
}

} // end Queens

2 个答案:

答案 0 :(得分:2)

您需要在placeQueens()方法中更改while循环

while ( !queenPlaced && (row <= BOARD_SIZE)  )  {...}

while循环应该是&lt;确保您永远不会尝试以索引BOARD_SIZE访问您的电路板。一旦行== BOARD_SIZE,您将尝试访问该板,这将使您看到的索引超出范围异常。将其更改为以下

while ( !queenPlaced && (row < BOARD_SIZE)  )  {...}

此外,在您的setQueen(...)和removeQueen(...)函数中,您永远不会进行边界检查,并假设您可以使用传入的参数访问该板。在设置或移除电路板阵列中的后置元件之前,您需要确保两个值都小于BOARD_SIZE。

private void setQueen(int row, int column) {
    if(row - 1 < BOARD_SIZE && column - 1 < BOARD_SIZE)
        board[row-1][column-1] = QUEEN;
} // end setQueen

private void removeQueen(int row, int column) {
   if(row - 1 < BOARD_SIZE && column - 1 < BOARD_SIZE)
       board[row-1][column-1] = EMPTY;
} // end setQueen

最后,既然您正在申请自己的1个,那么您应该将主要电话改为(Credit @Ian Mc)

q.placeQueens(1);

但是,如果您想简化程序,则不应该应用偏移量,因为这通常会引入用户错误。 以下是您应该如何使您的程序无偏移

(1)在isUnderAttack方法中添加检查,以确保在使用仅检查0和更大值的简单检查访问它们之前查看电路板中的有效行和列

private boolean isUnderAttack(int row, int column) {
// check column
for (int i=0; i<row-1; i++){
    /* add a check to ensure the column offset index is valid */
    if (column - 1 >= 0 && board[i][column-1]==1){
        return true;
    }
}
// check row
for (int i=0; i<column-1; i++) {
    /* add a check to ensure the row offset index is valid */
    if (row - 1 >= 0 && board[row-1][i] == 1){
        return true;
    }
}

(2)然后从删除和设置后置方法

中删除偏移量
private void setQueen(int row, int column) {
    if(row < BOARD_SIZE && column < BOARD_SIZE)
        board[row][column] = QUEEN;
} // end setQueen

private void removeQueen(int row, int column) {
   if(row < BOARD_SIZE && column < BOARD_SIZE)
       board[row][column] = EMPTY;
} // end setQueen

(3)确保在placeQueens(...)方法中从0循环到BOARD_SIZE - 1

while ( !queenPlaced && (row < BOARD_SIZE)  )  {

(4)最后从索引0开始

q.placeQueens(0);

输出

| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0 |
| 0 || 0 || 0 || 0 || 0 || 0 || X || X |
| 0 || 0 || 0 || 0 || 0 || X || 0 || 0 |
| 0 || 0 || 0 || 0 || X || 0 || 0 || 0 |
| 0 || 0 || 0 || X || 0 || 0 || 0 || 0 |
| 0 || 0 || X || 0 || 0 || 0 || 0 || 0 |
| 0 || X || 0 || 0 || 0 || 0 || 0 || 0 |
| X || 0 || 0 || 0 || 0 || 0 || 0 || 0 |

答案 1 :(得分:1)

q.placeQueens(0); // here is the Error 

因为你要设置女王

int row = 1;
.
.
.          
setQueen(row, column);  // The program will enter with row 1 and column 0

并且

private void setQueen(int row, int column) { 
    board[row-1][column-1] = QUEEN; // Here comes with row=1 and column 0
} 

使用

进行测试
q.placeQueens(1); 

正在显示

| X || 0 || 0 || 0 || 0 || 0 || 0 || 0 |
| 0 || 0 || 0 || 0 || X || 0 || 0 || 0 |
| 0 || X || 0 || 0 || 0 || 0 || 0 || 0 |
| 0 || 0 || 0 || 0 || 0 || X || 0 || 0 |
| 0 || 0 || X || 0 || 0 || 0 || 0 || 0 |
| 0 || 0 || 0 || 0 || 0 || 0 || X || 0 |
| 0 || 0 || 0 || X || 0 || 0 || 0 || 0 |
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0 |

我建议您查找一些有用的java调试技巧(EclipseIntelliJ)。