【问题标题】:Is this backtracking approach for N Queen problem incorrect?N Queen问题的这种回溯方法不正确吗?
【发布时间】:2020-08-28 20:41:18
【问题描述】:

N Queen 问题的行为不恰当,即它在使用 long long int 时给出了一些输出(虽然不正确),但在 int 的情况下,它给出了所有元素为 -1 的板数组。

代码是:

  #include<iostream>
  #include<iomanip>
  #include<cstring>

  using namespace std;
  const int d=4;

 //fills 0 to all the positions that are unsafe due to queen placed at (x,y)

  void fill(int board[d][d],int x,int y){
    for (int i = 0; i < d; ++i)
    {
      //for row and column
      board[i][y]=0; 
      board[x][i]=0;
    }
    //for the diagonal following i-1 & j-1 pattern
    for(int i=x,j=y; i>=0 && j>=0 ; --i,--j){
      board[i][j]=0;
    }
    //for the diagonal following i+1 & j+1 pattern
    for(int i=x,j=y; i<d && j<d ; ++i,++j){
      board[i][j]=0;
    } 
    //for the diagonal following i-1 & j+1 pattern
    for(int i=x,j=y; i>=0 && j<d ; --i,++j){
      board[i][j]=0;
    }
    //for the diagonal following i+1 & j-1 pattern   
    for(int i=x,j=y; i<d && j>=0 ; ++i,--j){
      board[i][j]=0;
    }    
  }


 //fills -1, i.e. clears the positions that were filled earlier due to queen at (x,y)
  void unfill(int board[d][d],int x,int y){
    for (int i = 0; i < d; ++i)
    {
      board[i][y]=-1;
      board[x][i]=-1;
    }
    for(int i=x,j=y; i>=0 && j>=0 ; --i,--j){
      board[i][j]=-1;
    }
    for(int i=x,j=y; i<d && j<d ; ++i,++j){
      board[i][j]=-1;
    } 
    for(int i=x,j=y; i>=0 && j<d ; --i,++j){
      board[i][j]=-1;
    }
    for(int i=x,j=y; i<d && j>=0 ; ++i,--j){
      board[i][j]=-1;
    } 

  }


  void printboard(int board[d][d]){
    for (int i = 0; i < d; ++i)
    {
      for (int j = 0; j < d; ++j)
      {
        cout<<setw(3)<<board[i][j]<<" ";
      }cout<<endl;
    }
  } 


  bool solve(int board[d][d],int queenno,int x,int y){
    //Returns true if all the queens are placed properly
    if(queenno==4){
      return true;
    }

    for (int i = x; i < d; ++i)
    {
      for (int j = y; j < d; ++j)
      {
        // If the position is unoccupied or safe i.e. value is -1
        if(board[i][j]==-1){
          fill(board,i,j); //assigns 0 to the places that are unsafe due to queen
          board[i][j]=1;  // places the queen at i,j
          queenno++;

          bool ans=solve(board,queenno,i,j);
          if(ans==false){
            unfill(board,i,j);  // assigns -1, i.e. backtracks
            queenno--;
            board[i][j]=-1;    // clears the earlier position of the queen
          }
        }

      }
    }
    // If can't place all the queens return false
    if(x==d-1 && y==d-1 && queenno<4){
      return false;
    }

  }



  int main()
  {
    // Creating a board of size 4x4 and assigning -1 to all its element
    int board[d][d]; 
    memset(board,-1,sizeof(board));

    bool ans=solve(board,0,0,0);
    if(ans)
      printboard(board);
    else
      cout<<"Can't print";

    return 0;
  }

使用 long long int 时给出的输出(虽然错误)是

  0  -1   0  -1 
  0   0   0  -1 
  1   0   0   0 
  0   0   1   0

请说明回溯出错的地方以及为什么在使用 int 而不是 long long int 时程序没有输出(即所有元素 -1)。

【问题讨论】:

  • How to debug small programs。使用调试器并单步执行您的代码,以查看代码在何处采用与您计划不同的路径,或变量设置为您未预期的值。
  • N-Queens 可以在多项式时间内求解。您使用回溯是有原因的吗?
  • @WillemVanOnsem 我只是在学习回溯。你能告诉回溯哪里出错了吗?

标签: c++ c algorithm c++11 c++14


【解决方案1】:

嗯,首先,你的算法还可以更好。如果您想改进您的算法,请查看“约束满足问题”。还有一些地方可以优化你的代码。

  #include<iostream>
  #include<iomanip>
  #include<cstring>

  using namespace std;
  const int d=4;

 //fills 0 to all the positions that are unsafe due to queen placed at (x,y)

void doFill(int* x) {
    if(*x != 1) {
        *x = 0;
    }
}

  void fill(int board[d][d],int x,int y){
    for (int i = 0; i < d; ++i)
    {
      //for row and column
      doFill(&board[i][y]); 
      doFill(&board[x][i]); 
    }
    //for the diagonal following i-1 & j-1 pattern
    for(int i=x,j=y; i>=0 && j>=0 ; --i,--j){
      doFill(&board[i][j]); 
    }
    //for the diagonal following i+1 & j+1 pattern
    for(int i=x,j=y; i<d && j<d ; ++i,++j){
      doFill(&board[i][j]); 
    } 
    //for the diagonal following i-1 & j+1 pattern
    for(int i=x,j=y; i>=0 && j<d ; --i,++j){
      doFill(&board[i][j]); 
    }
    //for the diagonal following i+1 & j-1 pattern   
    for(int i=x,j=y; i<d && j>=0 ; ++i,--j){
      doFill(&board[i][j]); 
    }    
  }


 //fills -1, i.e. clears the positions that were filled earlier due to queen at (x,y)
  void unfill(int board[d][d],int x,int y){
    board[x][y] = -1;  

    for (int i = 0; i < d; ++i)
    {
        for(int j = 0; j < d; ++j) {
            if(board[i][j] != 1) {
                board[i][j] = -1;
            }
        }
    } 

  for (int i = 0; i < d; ++i)
    {
        for(int j = 0; j < d; ++j) {
            if(board[i][j] == 1) {
                fill(board, i, j);
            }
        }
    } 

  }


  void printboard(int board[d][d]){
    for (int i = 0; i < d; ++i)
    {
      for (int j = 0; j < d; ++j)
      {
        cout<<setw(3)<<board[i][j]<<" ";
      }cout<<endl;
    }
  } 


  bool solve(int board[d][d],int queenno,int y){
    //Returns true if all the queens are placed properly
    if(queenno==d){
      return true;
    }
      if(y >= d) {
          return false;
      }

  for (int j = 0; j < d; ++j)
  {
    // If the position is unoccupied or safe i.e. value is -1
    if(board[y][j]==-1){
      fill(board,y,j); //assigns 0 to the places that are unsafe due to queen
      board[y][j]=1;  // places the queen at i,j
      queenno++;
        cout << "PLACE at " << j << "," << y << endl;
        printboard(board);
        if(solve(board,queenno,y+1)) {
            return true;
        }
        cout << "BT" << endl;
        unfill(board,y,j);  // assigns -1, i.e. backtracks
        queenno--;
        printboard(board);
    }

  }

    return false;
  }



  int main()
  {
    // Creating a board of size 4x4 and assigning -1 to all its element
    int board[d][d]; 
    memset(board,-1,sizeof(board));

    bool ans=solve(board,0,0);
  if(ans) {
      cout << "RESULT:" << endl;
      printboard(board);
  }
    else
      cout<<"Can't print";

    return 0;
  }

您的回溯和解决问题做得不是很好。这应该可以解决它。

【讨论】:

  • solve() 中的参数数量减少了,更具体地说,您已将 (x,y) 替换为 (y),因此变得更容易了。除了有效的算法,我还能从参数缩减中学到什么。
  • 嗯,我这样做的原因是没有必要搜索整个板,只需搜索下一行。请注意,我并不是说这是超级有效的解决方案,它可以做得更好。
  • 你能告诉我为什么板数组在我的代码中填充了-1(请参阅问题的最后几行)以及 doFill() 函数如何提供帮助。
  • 在你的回溯中,你用 -1 覆盖了你之前皇后的零。我的回溯就是这样工作的,我用-1替换除了皇后之外的所有东西。 doFill 方法将 0 放置到给定位置(如果没有皇后) - 我使用该方法是因为它比将 if 放在任何地方更容易。替换完所有东西后,我为每个女王重建了不安全的领域
【解决方案2】:

输出中有-1 的原因是solve 函数末尾缺少return true;。没有返回值,它是一个未定义的输出,所以它会产生疯狂的结果。

【讨论】:

  • 好吧,这并没有帮助:(我认为 if(queenno==4) return true; 做的工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
相关资源
最近更新 更多