n皇后问题(回溯法)

当已经放置了一部分皇后以后,对应生成了排列的一部分,可能剩余的皇后无论怎样放置都是不合法的。例如图B中https://blog.csdn.net/qq_36666756/article/details/82958653。当已经放置三个皇后后(对应生成了一部分排列,即351),可以发现剩下的两个皇后无论怎么放置都会产生冲突,就不用继续往下递归了。

#include<cstdio>
#include<stdlib.h>
const int maxn=10;
int n,P[maxn],hashTable[maxn]={false};
int count=0;
/*就是按照一行一行的递归,把每一行分成一个子问题*/ 
void generateP(int index)  //index表示的是列号 
{
	if(index==n+1)//递归边界,生成一个合法的方案 
	{
		count++;//能到达这里的一定是合法的 
		return;
	} 
	for(int x=1;x<=n;x++){ //第x行
		if(hashTable[x]==false)//第x行还没有皇后 
		{
		    bool flag=true;//true表示当前皇后和之前的皇后不会冲突
			 for(int pre=1;pre<index;pre++)//遍历之前的皇后,为什么是pre<index是因为在一个子问题时index在不断增加,只要前面的皇后的位置确定了,后面的
			  //就不用遍历了
			  {
			  	//第index列的皇后的行号为x,第pre列皇后的行号为p[pre] 
			  	if(abs(x-P[pre])==abs(index-pre))
			  	{
			  		flag=false;
			  		break;
			  	}
			  }
			if(flag)//如果可以吧皇后放在第x行
			{
				P[index]=x;//令第index列的皇后的行号为x
				hashTable[x]=true;//第x行被占用
				generateP(index+1);//处理下一行皇后,index+1表示下一行是因为当上一个子问题未达边界index表示的是列,到达边界后,index
				//的含义就不是列的含义了,表示的是下一个子问题了表示的是下一行了,应为最开始传进来的是表示第几个也就是第几行。 
				hashTable[x]=false;//表示其中一个子问题递归完 
				
				 
			} 
		}
		
		 
	}
	
}


int main()
{
	n=8;
	generateP(1);
	printf("%d",count); 
	return 0; 
}

暴力法与递归回溯法的区别:

暴力法是要计算完全部的排列才计算其中的排列是否满足n皇后的条件,也就是要在边界条件里面来判断是否满足条件。暴力法中的边界条件中的第二个循环j=i+1是应为两个皇后的位置不能相同,相同后就表示在一个位置上了,一个位置上就相当于少了一个位置。

回溯法中是将每一行看做一个子问题,通过不断迭代求得这些子问题的解是否满足条件。也就是从1-n行中,先计算第一行,然后不断计算增加的列,如果在增加的列的过程中,如果遇到不满足条件的情况就退出,迭代下一个满足条件的排列。其中index在generateP()中表示下一行也就是下一个子问题,在for循环中是表示下一列,这种列是变化的,应为index是在递归中的过程中需要通过执行index+1来执行增加来达到边界,同时,index也为了当前面满足皇后的位置放置,但是在index后面几个不满足条件的情况下就停止循环,表示不满足位置放置的条件。这些条件使index被混用了。

猜你喜欢

转载自blog.csdn.net/qq_36666756/article/details/82988999