[LeetCode][C++]八皇后及N皇后的解法

八皇后及N皇后的解法

首先看看八皇后问题:

在8X8的国际象棋棋盘上放置8个皇后,使这8个皇后中任意两个不在同一行、同一列、同一斜线上。试求出可能的解法以及总的解法个数。

分析:
(1)此问题的解必然是一个长度为8的向量,即在64个格子中选取8个,即C 8(上)64(下) = 4.426*10^9种方案,但此思路消耗太大
(2)如果我们这样想,设定一个数列loca[8],其中loca[i]代表第i行的皇后所在的列数,由于皇后不在同一行同一列,因此可供选择集合石{0,1,2,3,4,5,6,7},而此时的解集合即是8!= 40320 比(1)的消耗少了很多倍。

此时,我们再来看如何用算法求解这个问题:

这个问题可以找到一个解空间,而这个解空间是一个层数为9的完全二叉树,每一个结点都有8个子结点,所以,现在我们已经确定了解空间的结构,下一步是找到他的剪枝函数。

由于从backtrace(0)开始,向下纵深对应于棋盘中的行,所以下一行的元素不会和上一个元素在同一行,现在只要判断这个元素是否和前面已经摆好的皇后在同一列或者同一斜线上即可。

同一列的判断:loca[i] = loca[j]

同一斜线,因为是45°角,或者135°角,在斜率为1时,对点(a,b)和(c,d),a+b=c+d,而对斜率为-1时,a-b = c - d,两者移项可得,a-c = d - b 和 a - c = b - d,因此最终可以归纳为|a-c|=|b-d|。满足剪枝条件的可以直接去掉,剩下的即为正确答案。

将此问题推广,上述的方法实际上是适用于n皇后问题的,所以在代码中只需要改变n的值即可得到不同问题的正确解答。

代码:
此代码可动态求解n皇后问题,只需改变#define n 8中的8即可

#define n 8//这里可以任意改变n的值得到N皇后问题的解
int sum = 0;//记录总解的个数
int loca[n] = { 0 };  //loca[i]代表第i行的皇后所在的列数

int place(int k)
{	
	for (int i = 0; i < k; i++)//对前面的t个已放置好的皇后依次考察
		if ((fabs(i - k) == fabs(loca[i] - loca[k]) || loca[i] == loca[k]))  //如果满足在同一斜线或者同一列			
			return 0;
	return 1;
}

void queen(int t)
{
	int i;
	if (t >= n)//到达最底层无法纵深,sum++
	{
		sum++;
		for (i = 0; i < n; i++)
			printf("%d ", loca[i]);
		printf("\n");
	}
	else
	{
		for (i = 0; i < n; i++)//对该结点的n个子结点依次搜索
		{
			loca[t] = i;//第t行第i列
			if (place(t))
				queen(t + 1);//如果此列可放置,则沿着这点继续搜寻下一层
			loca[t] = 0;   
		}
	}
}



int main()
{
	queen(0);//从第0层开始回溯
	printf("%d\n", sum);//输出解的个数

	return 0;
}

参考链接:
[1] longchanglin0609:八皇后及N皇后的解法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值