回溯算法_八皇后问题的递归与非递归两种方法
问题描述
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
解题思路
定义一个一维数组a[8],下标表示行数,值表示列数:a[行]=列
使用回溯算法,在第k行放置皇后时,逐列测试安全性,如果安全,在安全位置放置皇后,不安全,则继续测试下一行,即第k+1行
如果整行都无法放置,则返回k-1行,将a[k-1]移值下一列,重复测试
非递归方法
#include<iostream>
#include <cmath>
using namespace std;
#define N 8
int a[N+1];
void show()
{
for(int i = 1; i <= N; i++)
cout << a[i] << " ";
cout << endl;
}
// 对角线和列的约束条件
int check(int k)
{
for(int i = 1; i < k; i++)
if(abs(a[i] - a[k]) == abs(i - k) || a[i] == a[k])
return 0;
return 1;
}
void backdata()
{
int k = 1;
int count = 0;
a[1] = 0;
while(k > 0)
{
a[k] += 1;
while(a[k] <= N && check(k) == 0) // 第k个皇后的搜索位置
a[k] += 1;
if(a[k] <= N)
if(k == N) // 找到一组解
{
show();
count++;
}
else
{
k++; // 放置第下一个个皇后
a[k] = 0; // 注意下一个皇后恢复至第一列
}
else k--; // 回溯
}
cout << "ans: " << count;
}
int main()
{
backdata();
}
递归方法
#include<iostream>
#include <cmath>
using namespace std;
#define N 8
int a[N], count=0;
void show()
{
for(int i = 0; i <= N; i++)
cout << a[i] << " ";
cout << endl;
}
// 对角线和列的约束条件
int check(int k)
{
for(int i = 0; i < k; i++)
if(abs(a[i] - a[k]) == abs(i - k) || a[i] == a[k])
return 0;
return 1;
}
void eight_queen(int n) // 递归回溯
{
for(int i = 0; i < N; i++)
{
a[n] = i; // 第k个皇后的搜索位置
if(check(n))
{
if(n == N - 1) // 找到一组解
{
show();
count++;
}
else
{
eight_queen(n + 1); // 放置第下一个个皇后
}
}
}
}
int main()
{
eight_queen(0); // 从第一行开始
cout << count;
}