codeup 2046 八皇后
题目描述:
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将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
思路:
全排列递归。填充完第一个字符后,再填充一个未出现的字符,依次类推,返回条件数组下标超出n,每个位置的填充都要填入所有未在前面位置出现的的字符,完成首字符为1 的填充,将以上步骤循环n次,完成全排列。也由于一个串中字符不重复出现,需要有个数组记录在当前填充的串中是否已出现将要出现的字符,并且要在每次返回结果是恢复记录。
本身是全排列问题:把8*8方格抽象成长度为8的字符数组,下标表示行(列),对应值表示列(行)。在全排列的基础上中找出没有斜线(abs(i-j)==abs(p[i]-p][j]))字符串。但是有的串在开始最已经不能成为结果串,后续的检查是没有的必要的。所以为了提高效率,在每次填充前先判断次字符是否与前面已填充好的各个字符存在斜线,若存在,直接跳出循环,放弃该字符的填入,否则进行下一个位置的递归。
出现的问题:
1、本题的要求输出n组满足条件的第i个序列,我以为只要对每次符合条件的序列计数,只要i和次数匹配就输出,但是i并不是按照大小顺序,就是说会出现需要输出过去的序列的情况,又由于我是用数组存放的i,导致如果第一个不被匹配,后面的就无法被匹配,导致一直没有结果输出。解决方法是每次将计数器遍历存i 的数组,匹配则把带输出序列保存在和相同位置数组中。
2、提交时编译出错:abs()用g++编译时,不光需要加上“#include<math.h>”,还要加上“#include<stdlib.h>”
AC代码:
#include<cstdio>
#include<math.h>
using namespace std;
int count=0,times=0; // count记录满足条件序列个数,要输出几组
int b[100]={0};//要输出序列的编号注意并不是按序
int out[100][9];//保存结果,用以按序输出
bool flag=false;//存在对角线
int n=8;//8*8矩阵
int p[9]={0};//存放当前列;
bool hashTable[9]={false};//存放散列数组,用以判断数字是否在当前数组中出现过
void func(int index)
{
if(index==n+1) //结束条件
{
count++;
for(int i=0;i<times;i++)
{
if(count == b[i])
{
for(int j=0;j<=n;j++)
{
out[i][j]=p[j];
}
}
}
return;
}
for(int x=1;x<=n;x++)
{
if(hashTable[x]==false)
{
p[index]=x;
hashTable[x]=true;
flag=false;
for(int j=1;j<index;j++) //判断是否在一条斜线上
{
if(abs(j-index) == abs(x-p[j])) //最新填写的一个数依次与当前数组的所有数 判断是否是斜线
{
flag=true;
break;
}
}
if(!flag) func(index+1);
hashTable[x]=false;//返回上层递归,在上层递归中x是未出现的;
}
}
}
int main()
{
while(scanf("%d",×)!=EOF)
{
for(int i=0;i<times;i++)
{
scanf("%d",&b[i]);
}
func(1);
for(int i=0;i<times;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d",out[i][j]);
}
printf("\n");
}
count=0;
}
}