回溯法其实也是一种搜索算法,它可以方便的搜索解空间。
回溯法解题通常可以从以下三步入手:
1、针对问题,定义解空间
2、确定易于搜索的解空间结构
3、以深度优先的方式搜索解空间,并在搜索的过程中进行剪枝
回溯法通常在解空间树上进行搜索,而解空间树通常有子集树和排列树。
针对这两个问题,算法的框架基本如下:
用回溯法搜索子集合树的一般框架
void backtrack(int t){
if(t > n) output(x);
else{
for(int i = f(n,t); i <= g(n,t);i++){
x[t] = h(i);
if(constraint(t) && bound(t)) backtrack(t+1);
}
}
}
网上看到些非递归解法,需要申请了些额外空间,我这里没有另外开辟空间,仅供参考,如果有问题,请留言。
不过我这里没考虑算法效率,网上有用公式求解,还有利用位操作进行计算的,有兴趣的可以关注下。
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
void Queen_n(int n);
int main()
{
int n;//N皇后
scanf("%d",&n);
Queen_n(n);
return 0;
}
bool place(int *x,int col,int n)
{
for(int i=0;i<col;i++)
{
if( x[col] == x[i] || abs(i-col) == abs(x[col]-x[i]) )
return false;
}
return true;
}
void BackTracing(int *x,int &sum,int t,int n)
{
if( t > n-1 )
{
sum ++;
printf("Column\tRow\n");
for(int i=0;i<n;i++)
printf("%3d\t%d\n",i,x[i]);
}
else
{
for(int j=0;j<n;j++)
{
x[t] = j;
if( place(x,t,n) )
{
BackTracing(x,sum,t+1,n);
}
}
}
}
void Back_not_resur(int *x,int &sum,int n)//非递归解法
{
int i=0,j=0;
x[i] = -1; //初始化为-1
while( i<n && i>=0)
{
x[i] += 1;
while(j<n) //如果不能放置,则该列上,继续放在下一行
{
x[i] = j;
if( !place(x,i,n) )
j++;
else break;
}
if( j<n)
{
if(i == n-1) //i=n-1,即求解到最后一列,即求解完成
{
sum++;
printf("Column\tRow\n");
for(int k=0;k<n;k++)
printf("%3d\t%d\n",k,x[k]);
j++; //继续求解下一个解
//break; //只求一个解,即结束
}
else //求解下一列,下一列从第0行开始放置
{
i++;
x[i] = -1;
j=0;
}
}
else //说明该列的所有行都不满足条件,则回溯到前一列,且位置是原来行号的下一行
{
j = x[i-1] + 1;
i--;
}
}
}
void Queen_n(int n)
{
int *X = new int[n];
int sum = 0;
for(int i=0;i<n;i++)
X[i] = -1;//X[i]表示第i列上,皇后所在的行号
//BackTracing(X,sum,0,n); //递归方法
Back_not_resur(X,sum,n);//非递归解法
printf("sum = %d\n",sum);
delete []X;
}