简体   繁体   English

C++ 使用递归回溯的数独求解器不起作用

[英]C++ Sudoku Solver using recursion backtracking not working

I'm trying to code a sudoku solver with recursion and backtracking.我正在尝试使用递归和回溯编写数独求解器。 But my code always returns false.但我的代码总是返回 false。 The SudokuSolver() traverses only the first row up to fourth column and then it stops and starts backtracking. SudokuSolver() 仅遍历第一行到第四列,然后停止并开始回溯。 The problem is that the backtracking continues until the first cell and finally returns false.问题是回溯一直持续到第一个单元格并最终返回 false。 As a result, none of the empty cells(cells with value "-1" ) are replaced by any other numbers(1-9) and the board remains as it is.结果,没有任何空单元格(值为“-1”的单元格)被任何其他数字(1-9)替换,并且棋盘保持原样。

Compiler shows [Done] exited with code=0 in 0.557 seconds编译器显示 [Done] 在 0.557 秒内以 code=0 退出

#include<iostream>
using namespace std;
# define N 9

bool SolveSudoku();
pair<int,int> FindUnassigned();
void PrintBoard();
bool NoConflict(int, int, int);
bool inRow(int,int);
bool inCol(int, int);
bool inGrid(int, int, int);
bool isFilled(pair<int,int>);

//board[row][col]==-1 indicates an empty position

int board[N][N] = {{3,-1,6,5,-1,8,4,-1,-1},
                   {5,2,-1,-1,-1,-1,-1,-1,-1},
                   {-1,5,7,-1,-1,-1,-1,3,1},
                   {-1,-1,3,-1,1,-1,-1,8,-1},
                   {9,-1,-1,8,6,3,-1,-1,5},
                   {-1,5,-1,-1,9,-1,6,-1,-1},
                   {1,3,-1,-1,-1,-1,2,5,-1},
                   {-1,-1,-1,-1,-1,-1,-1,7,4},
                   {-1,-1,5,2,-1,6,3,-1,-1}};


int main() {
    if(SolveSudoku()) 
        PrintBoard();
    return 0;
}


bool SolveSudoku() {
    pair<int,int> pos = FindUnassigned();
    int row=pos.first;
    int col=pos.second;
    if(isFilled(pos)) { return true; }
      for(int num=1; num<=9; num++) {
        if(NoConflict(num,row,col)) {
            board[row][col]=num;
            SolveSudoku();
            board[row][col]=-1;
        }  
      }
    return false;
}

pair<int,int> FindUnassigned() {
    pair<int,int> pos;
    pos.first=-1;
    pos.second=-1;
    for(int r=0; r<N; r++) {
        for(int c=0; c<N; c++) {
            if(board[r][c]==-1) {
                pos.first=r;
                pos.second=c;
                return pos;
            } 
        }
    }
    return pos;
}

bool isFilled(pair<int,int> pos) {
    return (pos.first==-1 && pos.second==-1);
}

bool NoConflict(int num, int r, int c) {
    return ((!inRow(numenter code here,r)==false) && (!inCol(num,c)==false) && (!inGrid(num,r-r%3,c-c%3)==false));
}

bool inRow(int num, int r) {
    for(int c=0; c<N; c++) {
        if(board[r][c]==num) return true;
    }
    return false;
}

bool inCol(int num, int c) {
    for(int r=0; r<N; r++) {
        if(board[r][c]==num) return true;
    }
    return false;
}

bool inGrid(int num, int rf, int cf) {
    for(int r=0; r<3; r++) {
        for(int c=0; c<3; c++) {
            if(board[r+rf][c+cf]==num) return true;
        }
    }
    return false;
}

void PrintBoard() {
    for(int r=0; r<N; r++) {
        for(int c=0; c<N; c++) {
            cout<<board[r][c]<<"\t";
        }
 enter code here       cout<<endl;
    }
}

Recursive functions work exactly like non-recursive functions.递归函数的工作方式与非递归函数完全相同。
(This is the most important thing to understand about recursion.) (这是理解递归最重要的一点。)

Here:这里:

board[row][col]=num;
SolveSudoku();
board[row][col]=-1;

you ignore the result of the function call, so you will recurse until the board is filled, then backtrack completely and finally return false;你忽略了 function 调用的结果,所以你会递归直到板子被填满,然后完全回溯,最后return false; . .

What you probably want is (thoroughly untested):您可能想要的是(完全未经测试):

if (SolveSudoku())
{
    return true;
}

There is also a bug in NoConflict , which is equivalent to NoConflict中还有一个bug,相当于

bool NoConflict(int num, int r, int c) {
    return inRow(num,r) && inCol(num,c) && inGrid(num,r-r%3,c-c%3);
}

that is, there is no conflict if and only if num is already in the row, the column, and the grid.也就是说,当且仅当num已经在行、列网格中时,才没有冲突。

You probably meant that num should not be found anywhere:您可能的意思是num不应该在任何地方找到:

bool NoConflict(int num, int r, int c) {
    return !inRow(num,r) && !inCol(num,c) && !inGrid(num,r-r%3,c-c%3);
}

but added another negative by mistake.但错误地添加了另一个否定。

It's possible that there are more bugs than this.可能有比这更多的错误。

  • The SolveSudoku() needs to iterate untill all "cells" in the board has been visited. SolveSudoku() 需要迭代,直到棋盘中的所有“单元格”都被访问过。

  • The NoConflict() looked strange, so I split the checks for clarity. NoConflict() 看起来很奇怪,所以为了清楚起见,我拆分了检查。

  • Your example board has a conflicting value at [2][1] causing pre-mature termination.您的示例板在 [2][1] 处的值冲突,导致提前终止。

I added a validation routine, to ensure a valid board before attempting to solve.我添加了一个验证例程,以确保在尝试解决之前有一个有效的板。 The following seems to provide a solution of the Sudoku:以下似乎提供了数独的解决方案:

#include <iostream>
#include <cstdio>
using namespace std;
# define N 9

bool ValidateSudoku();
bool SolveSudoku();
bool FindUnassigned(pair<int,int>& pos );
void PrintBoard();
bool NoConflict(int, int, int);
bool inRow(int,int);
bool inCol(int, int);
bool inGrid(int, int, int);
bool isFilled(pair<int,int>);

int board[N][N] = {
  { 3,-1, 6,  5,-1, 8,  4,-1,-1},
  { 5, 2,-1, -1,-1,-1, -1,-1,-1},
  {-1, 5 /*this is wrong*/, 7, -1,-1,-1, -1, 3, 1},

  {-1,-1, 3, -1, 1,-1, -1, 8,-1},
  { 9,-1,-1,  8, 6, 3, -1,-1, 5},
  {-1, 5,-1, -1, 9,-1,  6,-1,-1},

  { 1, 3,-1, -1,-1,-1,  2, 5,-1},
  {-1,-1,-1, -1,-1,-1, -1, 7, 4},
  {-1,-1, 5,  2,-1, 6,  3,-1,-1}
};

int main() {
    std::cout<<"Solve:"<<std::endl;
    PrintBoard();
    std::cout<<std::endl;

    if (ValidateSudoku()) {
      if (SolveSudoku()) {
        std::cout<<"Solution:"<<std::endl;
        PrintBoard();
      }
      else {
        std::cout<<"Failed to solve"<<std::endl;
      }
    }
    else {
      std::cout<<"Board is invalid"<<std::endl;
    }
    return 0;
}


bool ValidateSudoku() {
  for (int row=0;row<N; row++) {
    for (int col=0; col<N; col++) {
      int num = board[row][col];
      board[row][col] = -1;
      if (num != -1) {
        if (inRow(num, row)) {
          return false;
        }

        if (inCol(num, col)) {
          return false;
        }

         if (inGrid(num, row-(row%3), col-(col%3))) {
          return false;
        }
      }
      board[row][col] = num;
    }
  }
  return true;
}

bool SolveSudoku() {
    pair<int,int> pos;
    while (FindUnassigned(pos)) {
      int row=pos.first;
      int col=pos.second;
      for(int num=1; num<=9; num++) {
        if(NoConflict(num,row,col)) {
            board[row][col]=num;
            if (SolveSudoku()) {
              return true;
            }

            board[row][col]=-1;
        }  
      }    
      return false;
    }
    return true;
}

bool FindUnassigned(pair<int,int>& pos ) {
    for(int r=0; r<N; r++) {
        for(int c=0; c<N; c++) {
            if(board[r][c]==-1) {
                pos.first=r;
                pos.second=c;
                return true;
            } 
        }
    }
    return false;
}

bool isFilled(pair<int,int> pos) {
    return (pos.first==-1 && pos.second==-1);
}

bool NoConflict(int num, int r, int c) {
    if (inRow(num, r)) {
      return false;
    }
    if (inCol(num, c)) {
      return false;
    }

    if (inGrid(num, r-(r%3), c-(c%3))) {
      return false;
    }
    return true;
    //I think this is buggy: return ((!inRow(num,r)==false) && (!inCol(num,c)==false) && (!inGrid(num,r-r%3,c-c%3)==false));
}

bool inRow(int num, int r) {
    for(int c=0; c<N; c++) {
        if(board[r][c]==num) return true;
    }
    return false;
}

bool inCol(int num, int c) {
    for(int r=0; r<N; r++) {
        if(board[r][c]==num) return true;
    }
    return false;
}

bool inGrid(int num, int rf, int cf) {
    for(int r=0; r<3; r++) {
        for(int c=0; c<3; c++) {
            if(board[r+rf][c+cf]==num) return true;
        }
    }
    return false;
}

void PrintBoard() {   
    for(int r=0; r<N; r++) {
        if (0 == (r % 3)) { std::cout<<std::endl; }
        for(int c=0; c<N; c++) {
           if (0 == (c % 3)) { std::cout<<" "; }
           std::cout.width(3);
           cout<<board[r][c]<<" ";
        }
        std::cout<<std::endl;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM