回溯法类似于穷举法,不过一边穷举一边剪枝,减少计算量。
以3皇后为例来说明穷举法和回溯法的异同:
穷举法:
回溯法:
可以看到,每走一步,回溯法都会判断一下,对于已经错误的情况就不往下走,因此回溯法快一些。
回溯法代码实现:
//n皇后问题
#define NUMBER 7//皇后个数
int sum = 0;//解个数
void display(bool chess[NUMBER+1][NUMBER+1])//打印n皇后位置
{
for (int row = 1; row <= NUMBER; ++row)
{
for (int col = 1; col <= NUMBER; ++col)
{
if (true == chess[row][col])
{
cout << col << " ";
break;
}
}
}
cout << endl;
}
//判断chess[row][col]能不能走,从三个方向判断,有皇后挡道则返回false,能走返回true
bool judge(int row, int col, bool chess[NUMBER+1][NUMBER+1])
{
//垂直向上
for (int i = row-1; i >= 1; --i)
{
if (true == chess[i][col])
return false;
}
//左上
for (int r = row-1, c = col-1; r >= 1 && c >= 1; --r, --c)
{
if (true == chess[r][c])
return false;
}
//右上
for (int r = row-1, c = col+1; r >= 1 && c <= NUMBER; --r, ++c)
{
if (true == chess[r][c])
return false;
}
return true;
}
//回溯法,row表示当前行
void look_back(int row, bool chess[NUMBER+1][NUMBER+1])
{
if (row > NUMBER)//完成一个解
{
sum += 1;
cout << setw(3) << sum << ": ";
display(chess);
return;
}
for (int col = 1; col <= NUMBER; ++col)//穷举当前行的每个位置(列)
{
if (judge(row, col, chess))
{
chess[row][col] = true;//落子
look_back(row+1, chess);
chess[row][col] = false;//撤回
}
}
}
void N_Queen()
{
assert(NUMBER >= 1);
//棋盘二维数组,0下标占位不用。如果某行某列有皇后则记为true,没有则记为false
bool chess[NUMBER+1][NUMBER+1] = {false};
look_back(1, chess);
}
int main()
{
N_Queen();
return 0;
}
7皇后的结果如下:
7个数字每个代表位于当前行的第几列,以No.40为例: