C语言:八皇后问题----回溯算法

【问题引入】

在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。

 

【问题分析】

本题将要用到的是一种回溯的思想,为了更方便解释,先来看一道四皇后问题,也就是在4X4的棋盘上放四个皇后

首先,有一个4X4的棋盘

 我们用星星来表示皇后,首先将一个皇后放置(0,0)位置,红色的位置就不能再放置皇后,绿色位置还可以放置

那么接下来进行下一次放置,我们放置在(1,2)位置

此时我们发现,第二行已经无法放置皇后,本题中每一行每一列都应该有且仅有一个皇后,所以这种情况不符合条件

若将第二个皇后放在(1,3)位置

第二行还有一个位置可以放,那么继续

 

此时发现最后一行已经无法放置皇后,因此位置(0,0)不能放置皇后

接下来重新开始放置,将第一个皇后放置在(0,1)位置

 

第0行的皇后放在了(0,1)位置,那么第一行的皇后只能放在(1,3)位置

 

接下来第三个皇后放在(2,0)位置

 第四个皇后只能放置在(3,2)位置

此时发现已经完成了四皇后要求,讲图案进行旋转变换,很容易得到四皇后的第二种解法

 

可以验证一下,四皇后问题有且仅有这两种解法 

这是回溯算法的一个利用,那么接下来就是八皇后问题的代码

#include<stdio.h> 

int sum = 0; //方法总数
int chess[8][8]={0}; //8*8的棋盘

//判断此次放置是否合理|合理则返回1,否则返回0
int check(int row,int col)
{
	int i,j;
	for (i = 0; i < 8; i++) //判断皇后所在列
	{
		if (chess[i][col] == 1)
			return 0;
	}
	for (i = row, j = col; i >= 0 && j >= 0; i--, j--) //判断左下对角线
	{
		if (chess[i][j] == 1)
			return 0;
	}
	for (i = row, j = col; i >= 0 && j < 8; i--, j++) //判断右下对角线
	{
		if (chess[i][j] == 1)
			return 0;
	}
	return 1;
}
//打印输出结果
void print()
{
	int i,j; 
	printf("第%d种解法\n",sum+1);
	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (chess[i][j] == 1)
				printf("Q "); //皇后放置位置输出‘Q’
			else
				printf("# "); //其余位置输出‘#’
		}
		printf("\n");
	}
	printf("\n");
}
//寻找解法
void search(int row)
{
	if (row == 8) //此时0-7行均已正常放置皇后
	{
		print();
		sum++;
		return;
	}
	int col; //列
	for (col = 0; col < 8; col++) //假定将皇后放置在第row行第col列
	{
		if (check(row, col)) //若可以放置在此
		{
			chess[row][col] = 1; //修改该元素值为1
			search(row + 1); //进行下一次递归
			chess[row][col] = 0; //恢复被修改的值,否则会影响后续递归
		}
	}
}

int main()
{
	search(0);
	printf("共有%d种解法\n",sum);
	return 0;
}

 八皇后问题官方答案是92种解法

此代码还可以延伸到N皇后,但时间复杂度很高,运行时间较长。N=10时有724种解法,运行时间已经非常长了,若N=12,有14200种解法,可能需要运行数分钟

  • 23
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值