八皇后问题的递归解法与回溯优化

关于八皇后问题有很多种解法,今天只写一种利用全排列的解法,其他的一些解法看情况在整理补充。

全排列算法https://blog.csdn.net/qq_41706331/article/details/86521823

题目描述:

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

结题思路:

对于这个问题如果采用组合数的的方式来枚举每一种情况,那么将需要C_{n*n}^{n}次枚举,效率太低。

但换个思路,考虑到每行只能放置一个皇后,每列也只能放置一个皇后,如果把n列皇后所在的行号依次写出来那么就是1~8的一个

排列。因此只要枚举1~8的所有排列,统计其中合法的方案即可,只有n!个排列,比之前的枚举优秀很多。

#include<cstdio>
#include<cmath> 

int n;
int count=0;
int QueenList[10];
bool StatusTable[10]={0};

void NQueen(int index)
{
	if(index==n+1)
	{
		bool flag=true;
		int i,j;
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
			   if(abs(i-j)==abs(QueenList[i]-QueenList[j]))
			       flag=false;
		}
		if(flag)
		   count++;
		return;
	}
	int x;
	for(x=1;x<=n;x++)
	{
		if(StatusTable[x]==false)
		{
			QueenList[index]=x;
			StatusTable[x]=true;
			NQueen(index+1);
			StatusTable[x]=false;
		}
	}
 } 
 
 int main()
 {
//    printf("有几个皇后?");
// 	scanf("%d",&n);
// 	NQueen(1);
// 	printf("%d个皇后共有%d种合法方案\n",n,count);//我靠为什么这个编译器打印汉字是问号??? 
    printf("how many Queens?\t"); 
    scanf("%d",&n);
    NQueen(1);
    printf("there are %d schemes of %d Queens.\n",count,n);
 	
 	return 0;

 }

事实上,当已经放置了一部分皇后时,可能剩余的皇后无论怎样放置都不可能合法,这时就没必要往下递归了,直接返回上层即可。

利用回溯法优化刚刚的算法

void NQueen(int index)
{
	if(index==n+1)
	{
		count++;
		return;
	}
	
	int x,i;
	for(x=1;x<=n;x++)
	{
		if(StatusTable[x]==false)//如果第x行没有皇后 
		{
			bool flag=true; //flag为true表示在index位放入皇后无冲突,为false表示有冲突 
		    for(i=1;i<index;i++)//遍历之前的皇后 
		   {
//			    if(abs(x-i)==abs(QueenList[x]-QueenList[i]))    此时x还未放入index位 ,所以不能这么写 
                if(abs(index-i)==abs(x-QueenList[i]))//如果在index为放入x与之前某个皇后冲突 ,直接跳出循环,进入下一次外循环,将下一个x测试 
			      	{
			      		flag=false;
					    break;
				    } 
			} 
			if(flag==true)
			{
			    QueenList[index]=x;
			    StatusTable[x]=true;
		            NQueen(index+1);
			    StatusTable[x]=false;
	    	}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41706331/article/details/86522325