PAT 算法笔记 八皇后问题

问题描述:

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。

给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。

输入:

第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1 <= b <= 92)

输出:

输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。

输入样例:

3
6
4
25

输出样例:

25713864
17582463
36824175

解决思路:

问题解决主要通过三步:

(1)生成八皇后串

(2)排序

(3)输入与输出

其中后两步较为简单,核心为如何生成八皇后串。

从第一行开始,选择可以使用的列(hashTable[i] == false),这种选择方法规避了在同行同列上不可能有两个皇后,所以递归时只用判断是否在同一对角线上。

递归边界:扫描的行数大于8(等于9)即停止递归,每一次在新的一行插入皇后时,都判断了该皇后是否与先前的皇后发生了冲突,若发生冲突将停止递归。所以,在达到边界条件时,一定是一个合法的八皇后串,可以直接将其存入结果数组中。

递归式(递归调用):对于第index行,首先找到一个没有插入过皇后的列(i),表示在第index行第i列插入皇后。首先判断其与先前插入的皇后是否冲突,若冲突结束递归,若不冲突则将其计入临时存储串的数组中。将hashTable(i)设为true,表示该列已经不能用了。再递归调用generate(index + 1),为下一行选择皇后。最后将hashTable(i)设为false还原该列的状态。

完整代码:

#include <stdio.h>
#include <algorithm>
using namespace std;

//1-7用于表示对应列是否有皇后
bool hashTable[10] = {false};

//用于存储八皇后串,每个串共八位,用int就足够 
//num为res的下标 
int res[92] = {0}, num = 0; 

//用于临时存储现在的串 
int temp[10] = {0};

void generate(int index)
{
	//递归边界
	if(index == 9)
	{
		//若能达到递归边界则一定是一个合法的方案
		
		//将字符串转换为整数进行保存
		for(int i = 1; i <= 8; i++)
		{
			res[num] = res[num] * 10 + temp[i];
		}
		num++;
		return;
	} 
	
	for(int i = 1; i <= 8; i++)//第i列 
	{
		if(!hashTable[i])//该列没有皇后
		{
			bool flag = false;//flag用于标记该列是否冲突 
			
			//确保该列的皇后没有与之前的皇后发生冲突
            //如果发生冲突就停止递归,这样保证了如果达到递归边界为合法方案 
			for(int j = 1; j < index; j++)
			{
				if(abs(index - j) == abs(temp[j] - i))
				{//行列距离相等,表示在对角线上不满足条件
					flag = true;
					break;
				} 
			}
			 
			if(!flag)
			{//该列的皇后与之前的皇后没有发生冲突
				temp[index] = i;
				hashTable[i] = true;
				generate(index + 1);
				hashTable[i] = false;
			}
		} 
	}
}

int main()
{
	//生成八皇后串 
	generate(1); 
	
	//排序
	sort(res, res + num);
	
	//输入与输出 
	int N;
	scanf("%d", &N);
	while(N--)
	{
		int i;
		scanf("%d", &i);
		printf("%d\n", res[i - 1]); 
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值