n皇后问题--------回溯

关于问题的描述:n皇后问题是
来源于国际象棋中的皇后,通常叫8皇后问题,即在N*N的棋盘上,放置N个皇后,要求每一横行,每一列,每一对角线上均只能放置一个皇后,求可能的方案及方案数。

下面对n皇后问题进行分析:

1.一下是一个8*8的棋盘,从第一行开始放皇后,第一行皇后可以任意放,但每一行的方法都会影响后面的皇后放置


2.当第一行放好之后开始放的第2,3,4,5,6,7,8;但第一行会影响第二行,第二行会影响第三行的放置,第三行会影响的四行的放置.........

3.就这样在每一行的皇后可以有8种选择,但合法的是固定的,所以当本行出错时就得返回上一行检查或从新放置,如果上一行没有位置可行时,就得继续返回....一直返回知道返回第一行时,说明第一个皇后放在第一行不合适,然后到下一个位置,直到合适为止。

4.第一行放好继续放第二行,当某一行出错时,回退到上一行,直到放好然后继续往下进行,直到放置到最后一行结束。

代码实现思路:

   一:判断皇后放置位置合法性

    1.采用一维数组的下标表示第n个皇后(等同于第n行的皇后),数组元素为皇后的所在列。

    2.第n个皇后(第n行的皇后),a[n]为皇后所在列

    3.行列关系及判断存放位置的正确性,条件1:满足不同列及(a[i] != a[k])(i为之前放置的0~i行下标,a[i]为前i放置皇后的列);条件2:满足不在同一对角线及两个皇后坐标斜率不为1或-1(|i - k| != | a[i]-a[k]|);

二:回退控制

    1.每一行从第一列放置,合法时继续调用自身(放置函数进行下一行的放置),如果合法,放下一列,直到最后一列。

    2.当最后一列仍不合法时,回退上一行,进行上一行的下一列放置,依次放置判断,合法时下一行,不合法再回退直到合法再放下一行直到放完为止。

代码实现:

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;

class Nqueen
{
public:
	long NQueen()
	{
		cout<<"请输入皇后个数!"<<endl;
		cin>>n;
		sum = 0;
		a.reserve(n+1);
		init();
		backtrack(1);//找合理方案,放置皇后
		return sum;//合理方案个数
	}
	
private:
	bool place(int k)//放置位置合法性检验
	{
		for(int j = 1;j<k;j++)
		if((abs(k-j) == abs(a[k]-a[j]))||(a[k] == a[j])) return false;
		return  true;
	}
	void print()//打印每一行皇后放置列
	{
		for(int i = 1;i<= n;i++)
		{cout<<a[i]<<" ";}
		cout<<endl;
	}
	void init()//初始化每行皇后放置在第0列,当然在这第0列和第0行不再棋盘范围以方便下标(行)的控制和列的控制
	{
		for(int i = 0;i<= n;i++)
			a[i] = 0;
	}
	void backtrack(int t)//放置方法
	{
		if(t>n)//当当前所要放置的行大于棋盘的行是说明,已经找到一种方法
		{	sum++;//方法数目加1 
			print();//打印放置位置
		}
		else
			for(int i = 1;i<=n;i++)
			{
				a[t] = i;
				if(place(t))//满足时进行下一行放置,不满足时放置下下一列
				backtrack(t+1);
			}
			//当到这是说明没有可放置的列说明前几行有问题,回退
	}
	vector<int> a;//当前解
	int n;//皇后个数
	long sum;//求得解的可行方案数
};
int main()
{
	Nqueen q;
	cout<<q.NQueen()<<endl;
}

    


猜你喜欢

转载自blog.csdn.net/FangXiaXin/article/details/80527146
今日推荐