八皇后问题文档
八皇后问题详细的解法

若无法放下皇后则回到上一行, 即回溯
当n行的皇后都已确定后,我们 就找到了一种方案
check2 (int a[ ],int n)
queen21(例) 1 b加约束的枚举算法{//i多nt次i; 被调用,只是一重循环
{int a[9]; for (a[1]=1;a[1]<=8;a[1]++) for (a[2]=1;a[2]<=8;a[2]++)
八皇后问题
1
1八皇后问题背景 2盲目的枚举算法 3加约束的枚举算法 4回溯法及基本思想 5 回溯法应用 6八皇后问题的递归回溯算法 7八皇后问题的非递归回溯算法
2
【背景】 八皇后问题是一个以国际象棋为背
景的问题: 如何能够在 8×8 的国际象棋棋盘上
放置八个皇后,使得任何一个皇后都 无法直接吃掉其他的皇后?为了达到 此目的,任两个皇后都不能处于同一 条横行、纵行或斜线上。
for(a[8]=1;a[8]<=8;a[8]++) 此算法可读性很好,
{if (check(a,8)==0)continue; 体现了“回溯”。但
else for(i=1;i<=8;i+nt(a[i]); }
题,而不能解决任意
}}}}}}}
的n皇后问题。
18
2 回溯法应用-算法说明
按什么顺序去搜? 目标是没有漏网之鱼,尽量速度快。
5
2 【问题设计】盲目的枚举算法
a 盲目的枚举算法
通过8重循环模拟搜索空间中的88个状态;
按枚举思想,以DFS的方式,从第1个皇后在第1列开 始搜索,枚举出所有的“解状态”:
从中找出满足约束条件的“答案状态”。
回溯算法与八皇后问题N皇后问题Word版

回溯算法与八皇后问题(N皇后问题)1 问题描述八皇后问题是数据结构与算法这一门课中经典的一个问题。
下面再来看一下这个问题的描述。
八皇后问题说的是在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。
更通用的描述就是有没有可能在一张N*N的棋盘上安全地放N个皇后?2 回溯算法回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。
回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。
N皇后问题在N增大时就是这样一个解空间很大的问题,所以比较适合用这种方法求解。
这也是N皇后问题的传统解法,很经典。
下面是算法的高级伪码描述,这里用一个N*N的矩阵来存储棋盘:1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步3) 在当前位置上满足条件的情形:在当前位置放一个皇后,若当前行是最后一行,记录一个解;若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;若当前行是最后一行,当前列不是最后一列,当前列设为下一列;若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;以上返回到第2步4) 在当前位置上不满足条件的情形:若当前列不是最后一列,当前列设为下一列,返回到第2步;若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;算法的基本原理是上面这个样子,但不同的是用的数据结构不同,检查某个位置是否满足条件的方法也不同。
八皇后问题(回溯法)

void queen(int N)
{ //初始化N+1个元素,第一个元素不使用
int col[N+1]; //col[m]=n表示第m列,第n行放置皇后
int a[N+1]; //a[k]=1表示第k行没有皇后
int b[2*N+1]; //b[k]=1表示第k条主对角线上没有皇后
int c[2*N+1]; //c[k]=1表示第k条次对角线上没有皇后
int j,m=1,good=1;char awn;
for(j=0;j<=N;j++)
{a[j]=1;}
for(j=0;j<=2*N;j++)
{b[j]=c[j]=1;}
col[1]=1;col[0]=0;
do
{
if(good)
八皇后问题(回溯法)2009-08-11 12:03问题描述:
求出在一个n×n的棋盘上,放置n个不能互相捕捉的国际象棋“皇后”的所有布局,这是来源于国际象棋的一个问题。皇后可以沿着纵横和两条斜线4个方向互相捕捉。
解题思路:
总体思想为回溯法。
求解过程从空配置开始。在第1列~的m列为合理配置的基础上,再配置第m+1列,直至第n列也是合理时,就找到了一个解。在每列上,顺次从第一行到第n行配置,当第n行也找不到一个合理的配置时,就要回溯,去改变前一列的配置。
if(awn=='Q'||awn=='q')
exit(0);
while(col[m]==N) //如果本列试探完毕,则回溯
{
m--; //回溯
a[col[m]]=b[m+col[m]]=c[N+m-col[m]]=1;//标记m列col[m]行处没有皇后(所在行,对角线,次对角线上都没有皇后)
随机法 8皇后问题

回溯法与随机法比较: 回溯法与随机法比较:
N皇后问题一般是采用回溯法求解,但当N值 皇后问题一般是采用回溯法求解,但当 值 皇后问题一般是采用回溯法求解 较大时,回溯算法效率较低。 较大时,回溯算法效率较低。 引入随机算法, 引入随机算法,能保证每次找出的解是正确 但可能在一次求解过程中找不出可行解, 的,但可能在一次求解过程中找不出可行解,这 一点在程序运行过程中能得到体现。 一点在程序运行过程中能得到体现。 所以解决N皇后问题时, 所以解决 皇后问题时,我们可以先用随机 皇后问题时 函数产生一部分的解(这一部分可以占全部的三 函数产生一部分的解( 分之一),再用回溯法将其余的结果计算出来。 ),再用回溯法将其余的结果计算出来 分之一),再用回溯法将其余的结果计算出来。
2.回溯法与随机法结合,也就是,前k个皇后用随 2.回溯法与随机法结合,也就是, 回溯法与随机法结合 机法,后面的回溯。 机法,后面的回溯。 这样效率会提高很多。 这样效率会提高很多。 但是随机产生的k个皇后,回溯继续求解时不一定 但是随机产生的k个皇后, 能得到可行解。此时,需要重新运行算法。 能得到可行解。此时,需要重新运行算法。
姓名: 姓名:刘瑾 学号: 学号:31109016
一、8皇后问题算法描述 皇后问题算法描述
1.每个皇后放置的位置均随机 每个皇后放置的位置均随机 直接从每行的8个位置随机选择 直接从每行的 个位置随机选择 随机法 从每行的可行解中随机选择
不管用哪种随机法,都是算法一旦失败, 不管用哪种随机法,都是算法一旦失败, 就得重新运行。 就得重新运行。 算法成功,只找到一个解。 算法成功,只找到一个解。 多次成功找到的解不一定是同一个解。 多次成功找到的解不一定是同一个解。
运行结果: 运行结果:
八皇后问题

该算法的大概描述:
1.置当前行 当前列均为1 2.While当前行号(<=8) 3.检查 当前行,从当前列起逐列试探,寻找安全列号 4.If(找到安全号) 5.放置皇后,将列号记入栈中,并将下一行置成当前行,第一列置为当前列 6.否则回溯到上一行,移去该行已经放置的皇后,以该皇后所在列的下一列作为当 前列, 8结束程序。
八皇后问题
八数学家高斯1850年提出:在 8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任 意两个皇后都不能处于同一行、同一列或同一斜线上,问有 多少种摆法?八皇后在棋盘上分布的各种可能的数目非常大。 但是可以将一些明显不满足问题要求的格局排除掉,由于任 意两个皇后不可能同行,即每一行只能放置一个皇后,因此 将第i个皇后放置在第i行上。这样 在放置第i个皇后时,只要 考虑它与前i-1个皇后处于不同列和不同对角线位置上即可。
一般算法
用 数组a、b、c分别用来标记冲突,a数组代表列冲突,从a[0]~a[7]代表第0列到第 7列,如果某列上已经有皇后,则为1,否则为0; 数组b代表主对角线冲突,为b[i-j+7],即从b[0]~b[14],如果某条主对角线上已经 有皇后,则为1,否则为0; 数组c代表从对角线冲突,为c[i+j],即从c[0]~c[14],如果某条从对角线上已经有皇 后,则为1,否则为0; 从第一行起 逐个放置皇后,每放置一个皇后依次对第1,2......8列进行试探,若当 前 试探的列位置是安全的,则将该行的列位置保存在栈中,然后继续在下一行寻 找安全位置,若当前试探的列位置不安全,则用下一列进行试探,当8列的位置试 探完毕都未能找到安全位置时,就退栈回溯到上一行,修改栈顶保存的皇后位置, 然后继续试探。
八皇后问题有多少解

八皇后问题有多少解八皇后问题有92解。
皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。
如何将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 的皇后串//输入样例//2//1//92//输出样例//15863724//84136275解题思路一因为要求出92种不同摆放方法中的任意一种,所以我们不妨把92种不同的摆放方法一次性求出来,存放在一个数组里。
为求解这道题我们需要有一个矩阵仿真棋盘,每次试放一个棋子时只能放在尚未被控制的格子上,一旦放置了一个新棋子,就在它所能控制的所有位置上设置标记,如此下去把八个棋子放好。
当完成一种摆放时,就要尝试下一种。
若要按照字典序将可行的摆放方法记录下来,就要按照一定的顺序进行尝试。
也就是将第一个棋子按照从小到大的顺序尝试;对于第一个棋子的每一个位置,将第二个棋子从可行的位置从小到大的顺序尝试;在第一第二个棋子固定的情况下,将第三个棋子从可行的位置从小到大的顺序尝试;依次类推。
首先,我们有一个8*8的矩阵仿真棋盘标识当前已经摆放好的棋子所控制的区域。
用一个有92行每行8个元素的二维数组记录可行的摆放方法。
用一个递归程序来实现尝试摆放的过程。
基本思想是假设我们将第一个棋子摆好,并设置了它所控制的区域,则这个问题变成了一个7皇后问题,用与8皇后同样的方法可以获得问题的解。
1213:八皇后问题

1213:⼋皇后问题【题⽬描述】在国际象棋棋盘上放置⼋个皇后,要求每两个皇后之间不能直接吃掉对⽅。
【输⼊】(⽆)【输出】按给定顺序和格式输出所有⼋皇后问题的解(见样例)。
【输⼊样例】(⽆)【输出样例】No. 11 0 0 0 0 0 0 00 0 0 0 0 0 1 00 0 0 0 1 0 0 00 0 0 0 0 0 0 10 1 0 0 0 0 0 00 0 0 1 0 0 0 00 0 0 0 0 1 0 00 0 1 0 0 0 0 0No. 21 0 0 0 0 0 0 00 0 0 0 0 0 1 00 0 0 1 0 0 0 00 0 0 0 0 1 0 00 0 0 0 0 0 0 10 1 0 0 0 0 0 00 0 0 0 1 0 0 00 0 1 0 0 0 0 0...以下省略解题分析:关键在于斜线还有是否访问过,正斜与反斜⾓的特点#include<bits/stdc++.h>using namespace std;int a[10001],b[10001],w[10001],m[10001],tot=0;int print(){tot++;cout<<"No. "<<tot<<endl;for(int j=1;j<=8;++j){for(int i=1;i<=8;++i)if(j==a[i])cout<<1<<" ";else cout<<0<<" ";cout<<endl;}}int search(int j){for(int i=1 ;i<=8;++i){if(b[i]==0&&w[i-j+7]==0&&m[i+j]==0){a[j]=i;b[i]=1;w[i-j+7]=1;m[i+j]=1;if(j==8) print();else search(j+1);b[i]=0;w[i-j+7]=0;m[i+j]=0;}}}int main(){search(1);return 0;}记住限制条件是该列有没访问过,还有斜⾓两个⽅向。
皇后问题详细的解法

for(a[7]=1;a[7]<=8;a[7]++} )
for(a[8]=1;a[8]<=8;a[8]++){
if (check(a,8)=0) continue;
else
for(i=1;i<=8;i++)print(a[i]);
}
10
}
1 回溯法
有“通用的解题法”之称。 回溯法的基本做法是搜索,或是一种组织得井井有条
枚举得有个顺序,否则 轻则有漏的、重复的; 重则无法循环表示。
6
1.按什么顺序去查找所有的解 a.盲目的枚举算法
void main() {
int x[100]; for (x[1]=1;x[1]<=10;x[1]++) for (x[2]=1;x[2]<=10;x[2]++)
for (x[3]=1;x[3]<=10;x[3]++) for (x[4]=1;x[4]<=10;x[4]++) for (x[5]=1;x[5]<=10;x[5]++) for (x[6]=1;x[6]<=10;x[6]++) for (x[7]=1;x[7]<=10;x[7]++) for (x[8]=1;x[8]<=10;x[8]++) if (check(x)==0) { printf(x); }
}
该如何解决冲突的问题呢?
1.行;我们是按照行枚举的,保证了一行一个皇后; 2.列:判断是否存在x[i]=x[j] 3.对角线:主对角线的i-j与从对角线的i+j存在特殊关系,如 图:
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
八皇后问题文档
一,问题描述
能否在空棋盘上摆放八个皇后,使他们不互相侵犯,即任意的两个皇后不能在同一行或者是同一列。
二,算法思路
由于行坐标可看作不变的量,因此只要找出来不同的列坐即可,由于列坐标一定是从1到8 的序列,而且这些数字仅出现一次,因此用递归找到所有的序列,其中,把整个棋盘看作一个坐标轴,当有两点的斜率等于正负一或者为零和无穷大时,将他们跳过,直到遍历完成,打印这个序列,那么就可以得到皇后的放置方法。
三,算法描述
1,所调用的库函数
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define num 8
2,有一个检查斜率的函数check。
他的用途是检查这个8位数列是否满足斜率为正负一和零的情况,如果是的话,返回0,否则返回1。
int check(int k[])
{
int n,m;
for (n=0;n<7;n++)
for (m=n+1;m<8;m++)
if
(k[m]<1||k[m]>8||k[n]==k[m]||abs(k[n]-k[m])==abs(n-m)) //计算其两个相邻点斜率K,并且返回他的值K[m]<1或K[m]>8时,那么就可以认为他的斜率不存在了,由于斜率是传递的,所以可以这样检测,得到应有的情况
return(0);
return(1);
}
3,main函数
main()
{
int board[num]={8,7,6,5,4,3,2,1},j=0,*ptr;
/*board[num]代表棋盘上八行,由于八个皇后在棋盘上一定是每行一个,而且横坐标一定各不相同,即1--->8各出现一次,只要检测这些数列就可以找到八皇后的所有可能情况*/
for (ptr=board;board[7]<9;board[0]+=9)
{
for (ptr=board;ptr<&board[7];)
/*对12345678每次加9,直加到87654321*/
{
if (*ptr>9)
{
*(ptr+1)+=1;
*ptr-=10;
ptr++;
}
else
ptr+=8;
}
//向下一个进行,如果大于9的话,减十再作check
if (check(board))
/*检测八位数列,返回值为真则在屏幕上输出*/
{
for (ptr=board;ptr<=&board[7];ptr++)
printf("%d",*ptr);
printf("\n");
}
}
system("pause");
return 0;
}
4,测试报告
最终出现92种情况,随机取出十组检验,发现是可行的。
5,结论和心得
经过这次编程,再次熟悉了递归调用,强化了对递归的理解,并且发现了递归的简便之处以及其运用,以后还要认真学习递归。
并且学会了要耐心的调试程序。