递归求解N皇后问题

关键点分析提示:

①如何判断能否放置皇后?
答:如果仔细分析就知道,其实判断的范围就只有该皇后的前几行,比如这个图:

当你准备在第三行放四皇后的时候,你不需要管后面几行的情况,因为没有四皇后,也不需要管当前行的情况,因为一行只有一个皇后,所以判断的范围缩小,只需要在这个范围内没有皇后即可,如图:

如果你理解了这样的判断,那么如何判断,就可以参考我的代码里面的函数CanPut,if语句里面就给出了判断方法

②如何重新放置?
答:我们可以先假设这个位置能放置,具体到算法里面就是先把这个位置置为‘1’,然后再调用CanPut函数判断能否放,如果能,递归进入下一层,判断下一行的皇后摆放,并且当回溯回来的时候,要重新摆放,也就是‘1’要归0。那么这里我们就可以分析知道,无论是否可以Place,也就是无论是本来就不能摆放,还是摆放完后虽然可以当时回溯回来后又不能再摆放(因为要判断下一个位置),这个位置总是要归0的。所以为了使逻辑简单,不妨先假设能放,后面又取消这个位置,如此不至于留下皇后摆放的痕迹,给问题的处理带来困难。

③递归的出口在哪?
答:不难想到,递归求解N皇后问题不过是暴力破解,那么当所有的情况都试过了,自然递归的就结束了,具体讲,就是第一行的皇后已经没位置放了,递归就结束了。


以下是代码:

#include<stdio.h>
#define Debug
int count=0;
void Queen(int n,int l);
bool CanPut(int i,int j,int (*a)[8],int n);
void Print(int (*a)[8],int n);

int main()
{
	printf("请输入棋盘的规模\n");
	int n;
	scanf("%d",&n);

	Queen(n,0);
	if(count)
		printf("解的总数是:%d\n",count);
	else
		printf("无解\n");

	return 1;
}

int a[8][8]={0};

void Queen(int n,int l)
{
	if(l==n-1)//最后一行,递归出口
	{
		for(int j=0;j<n;j++)
		{
			if(CanPut(l,j,a,n))//是否能放置皇后
			{
				count++;
				a[l][j]=1;//标记位置
				Print(a,n);
				a[l][j]=0;//取消这个位置
			}
		}
		printf("\n");
	}
	else//不是最后一行
	{
		for(int j=0;j<n;j++)
		{
			a[l][j]=1;//假设这个位置可以放
			if(CanPut(l,j,a,n))//如果可以,递归进入下一行
				Queen(n,l+1);
			a[l][j]=0;//回溯回来后或者不可以放置皇后归0
		}
	}
	return;//如果是if,则递归出口,如果是else,则回溯到上一行
}

void Print(int (*a)[8],int n)
{//本算法打印出N皇后的解
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}
}

bool CanPut(int i,int j,int (*a)[8],int n)
{//本算法是判断该位置能否放皇后
	int s=0;
	for(int k=i-1;k>=0;k--)
	{
		s++;
		if(a[k][j]==1 || j+s<n&&a[k][j+s]==1 || j-s>=0&&a[k][j-s]==1)
			return false;
	}
	return true;
}


猜你喜欢

转载自blog.csdn.net/weixin_41133154/article/details/78986617