八皇后及N皇后问题
组合数学中的棋盘问题
组合数学中的棋盘问题棋盘问题是组合数学中一个经典而又有趣的问题,它涉及到在一个n × n 的棋盘上放置一定数量的棋子并满足特定的条件。
在本文中,我们将探讨棋盘问题的一些常见形式以及解决方法。
一、八皇后问题八皇后问题是指在一个 8 × 8 的棋盘上放置 8 个皇后,并且每个皇后都不能相互攻击,即任意两个皇后不得处于同一行、同一列或同一对角线上。
这个问题可以通过回溯法来解决。
我们可以逐行放置皇后,并在每一行中使用循环判断每个格子是否满足条件。
如果满足条件,则继续递归下一行;如果不满足条件,则回溯到上一行继续判断。
当所有皇后都放置完毕时,即找到了一种解法。
二、骑士周游问题骑士周游问题是指在一个 n × n 的棋盘上,骑士按照国际象棋中骑士的移动规则进行移动,需要从起始格子出发,经过棋盘的每个格子,最终回到起始格子,且每个格子只能经过一次。
这个问题可以通过深度优先搜索或者广度优先搜索来解决。
我们可以从起始格子开始,按照骑士的移动规则依次遍历所有相邻的格子,并标记已访问的格子。
当所有格子都被访问过,并且最后的格子可以与起始格子连通,则找到了一种解法。
三、数独问题数独问题是指在一个 9 × 9 的棋盘上填入数字,使得每一行、每一列和每一个 3 × 3 的小方格中的数字都是 1 到 9 的不重复数字。
这个问题可以通过回溯法来解决。
我们可以逐格填入数字,并在每个格子中使用循环判断每个数字是否满足条件。
如果满足条件,则继续递归下一个格子;如果不满足条件,则尝试下一个数字。
当所有格子都填满时,即找到了一种解法。
四、六角形拼图问题六角形拼图问题是指在一个六角形的棋盘上,使用特定形状的六角形块填满整个棋盘。
这个问题可以通过搜索算法来解决。
我们可以从一个起始位置开始,依次尝试放置不同形状的六角形块。
每次放置块后,判断是否满足放置要求。
如果满足要求,则继续递归下一个位置;如果不满足要求,则尝试下一个形状的块。
八皇后的n种放置方法
addqueen({},1)
博客园 用户登录 代码改变世界 密码登录 短信登录 忘记登录用户名 忘记密码 记住我 登录 第三方登录/注册 没有账户, 立即注册
八皇后的 n种放置方法
八皇后问题是一个以为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到 此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而 皇后个数也变成n。n = 1或n ≥ 4时问题有解。
-- 打印棋盘 function printsolutions(a)
for i=1,N do for j=1,N do io.write(a[i]==j and "q" or "-"," ") end io.write("\n")
end io.write("\n\n") end
function addqueen(a,n) if n > N then printsolutions(a) else for c = 1, N do if(isplaceok(a,n,c)) then a[n] = c addqueen(a,n+1) end end end
-- 皇后的数量 N=8
-- 判断皇后是否可以放置在棋盘上 function isplaceok(a,n,c)
for i=1,n-1 do if(a[i]==c) or (a[i]+i==c+n) or (a[i]-i==c-n) then return false end end
return true end
八皇后问题(经典算法-回溯法)
⼋皇后问题(经典算法-回溯法)问题描述:⼋皇后问题(eight queens problem)是⼗九世纪著名的数学家⾼斯于1850年提出的。
问题是:在8×8的棋盘上摆放⼋个皇后,使其不能互相攻击。
即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上。
可以把⼋皇后问题扩展到n皇后问题,即在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能互相攻击。
思路:使⽤回溯法依次假设皇后的位置,当第⼀个皇后确定后,寻找下⼀⾏的皇后位置,当满⾜左上、右上和正上⽅向⽆皇后,即矩阵中对应位置都为0,则可以确定皇后位置,依次判断下⼀⾏的皇后位置。
当到达第8⾏时,说明⼋个皇后安置完毕。
代码如下:#include<iostream>using namespace std;#define N 8int a[N][N];int count=0;//判断是否可放bool search(int r,int c){int i,j;//左上+正上for(i=r,j=c; i>=0 && j>=0; i--,j--){if(a[i][j] || a[i][c]){return false;}}//右上for(i=r,j=c; i>=0 && j<N; i--,j++){if(a[i][j]){return false;}}return true;}//输出void print(){for(int i=0;i<N;i++){for(int j=0;j<N;j++){cout<<a[i][j]<<" ";}cout<<endl;}}//回溯法查找适合的放法void queen(int r){if(r == 8){count++;cout<<"第"<<count<<"种放法\n";print();cout<<endl;return;}int i;for(i=0; i<N; i++){if(search(r,i)){a[r][i] = 1;queen(r+1);a[r][i] = 0;}}}//⼊⼝int main(){queen(0);cout<<"⼀共有"<<count<<"放法\n"; return 0;}。
八皇后问题详细的解法
若无法放下皇后则回到上一行, 即回溯
当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皇后问题
的解可以用一个n元向量X=(x1,x2,.....xn)表示,其中, 1≤ i≤ n且1≤ xi≤ n,即第n个皇后放在第i行第xi列上。 由于两个皇后不能放在同一列上,所以,解向量X必须满 足的约束条件为:xi≠ xj; • 若两个皇后的摆放位置分别是(i,xi)和(j,xj),在棋盘 上斜率为-1的斜线上,满足条件i-j=xi-xj;在棋盘上斜率为1 的斜线上,满足条件i+j=xi+xj;
else {
x[k]=0;//重置x[k],回溯 k=k-1;
}
} }
void main() { int n; printf("输入皇后个数n:\n"); scanf("%d",&n); queue(n); }
ห้องสมุดไป่ตู้
• for(i=1;i<=n;i++)
x[i]=0; k=1; while(k>=1) { x[k]=x[k]+1; //在下一列放置第k个皇后 while(x[k]<=n&&!place(k)) x[k]=x[k]+1;//搜索下一列 if(x[k]<=n&&k==n)//得到一个输出 { for(i=1;i<=n;i++) printf("%d ",x[i]); printf("\n"); //return;//若return则只求出其中一种解,若不return则可以继 续回溯,求出全部的可能的解 } else if(x[k]<=n&&k<n) k=k+1;//放置下一个皇后
N皇后问题及答案解
N皇后问题及答案解题⽬在⼀张N∗N的国际象棋棋盘上,放置N个皇后,使得所有皇后都⽆法互相直接攻击得到,(皇后可以直接攻击到她所在的横⾏,竖列,斜⽅向上的棋⼦),现在输⼊⼀个整数N,表⽰在N∗N的棋盘上放N个皇后,请输出共有多少种使得所有皇后都⽆法互相直接攻击得到的⽅案数。
例如下⾯这样的摆法,是4皇后的⼀个解 (1代表有皇后,0代表没有)0 1 0 00 0 0 11 0 0 00 0 1 0输⼊⼀个整数N,代表皇后的个数输出输出⽅案数样例输⼊样例输⼊14样例输⼊28样例输出样例输出12样例输出292⼀、DFS+回溯(1)设已经放好的皇后坐标为(i,j),待放⼊的皇后坐标为(r,c),则它们满⾜以下关系:(1)不同⾏,即 i ≠ r;(2)不同列,即 j ≠ c;(3)不在斜对⾓线上,即 |i-r| ≠ |j-c|.可以在⼀⾏逐列尝试,这样就不⽤考虑(1)了。
#include <iostream>#include <algorithm>#include <cstring>using namespace std;int n, tot = 0;int col[15] = {0}, ans[15] = {0}; //col[i]的值为第i⾏的皇后的列数的值,即j,ans[]数组⽤来存放结果bool check(int c, int r) //检查是否和已经放好的皇后冲突{for (int i = 0; i < r; i++)if (col[i] == c || (abs(col[i] - c) == abs(i - r))) //因为是逐⾏放置,所以只考虑纵向和斜向return false;return true;}void dfs(int r,int m) //在第r⾏放皇后,m表⽰⾏数{if(r==m){ //r==m,即皇后放到最后⼀⾏,满⾜条件,tot++,返回;tot++;return;}for(int c=0;c<m;c++) //在此⾏逐列尝试if(check(c,r)){ //检查是否冲突col[r]=c; //不冲突就在此列放皇后dfs(r+1,m); //转到下⼀⾏继续尝试}}int main(){cin>>n;for (int i = 0; i <= 13; i++) //算出所有N皇后的答案,先打表,不然会超时{memset(col, 0, sizeof(col)); //清空col,准备计算下⼀个N皇后问题tot = 0;dfs(0,i);ans[i] = tot;}cout << ans[n] << endl;return 0;}在上述程序中,dfs()⼀⾏⾏放置皇后,时间复杂度为O(N!);check()判断冲突,时间复杂度为O(N),总的为O(N*N!)!⾮常的⾼。
八皇后以及N皇后问题分析
⼋皇后以及N皇后问题分析⼋皇后是⼀个经典问题,在8*8的棋盘上放置8个皇后,每⼀⾏不能互相攻击。
因此拓展出 N皇后问题。
下⾯慢慢了解解决这些问题的⽅法:回溯法:回溯算法也叫试探法,它是⼀种系统地搜索问题的解的⽅法。
回溯算法的基本思想是:从⼀条路往前⾛,能进则进,不能进则退回来,换⼀条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满⾜某种要求的可能或最优的情况,从⽽得到整个问题的解。
回溯算法就是解决这种问题的“通⽤算法”,有“万能算法”之称。
N皇后问题在N增⼤时就是这样⼀个解空间很⼤的问题,所以⽐较适合⽤这种⽅法求解。
这也是N皇后问题的传统解法,很经典。
算法描述:1. 算法开始,清空棋盘。
当前⾏设为第⼀⾏,当前列设为第⼀列。
2. 在当前⾏,当前列的判断放置皇后是否安全,若不安全,则跳到第四步。
3. 在当前位置上满⾜条件的情况: 在当前位置放⼀个皇后,若当前⾏是最后⼀⾏,记录⼀个解; 若当前⾏不是最后⼀⾏,当前⾏设为下⼀⾏,当前列设为当前⾏的第⼀个待测位置; 若当前⾏是最后⼀⾏,当前列不是最后⼀列,当前列设为下⼀列; 若当前⾏是最后⼀⾏,当前列是最后⼀列,回溯,即清空当前⾏以及以下各⾏的棋盘,然后当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置; 以上返回第⼆步。
4.在当前位置上不满⾜条件: 若当前列不是最后⼀列,当前列设为下⼀列,返回到第⼆步; 若当前列是最后⼀列,回溯,即,若当前⾏已经是第⼀⾏了,算法退出,否则,清空当前⾏以及以下各⾏的棋盘,然后,当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置,返回第⼆步。
如何判断是否安全:把棋盘存储为⼀个N维数组a[N],数组中第i个元素的值代表第i⾏的皇后位置,这样便可以把问题的空间规模压缩为⼀维O(N),在判断是否冲突时也很简单, ⾸先每⾏只有⼀个皇后,且在数组中只占据⼀个元素的位置,⾏冲突就不存在了, 其次是列冲突,判断⼀下是否有a[i]与当前要放置皇后的列j相等即可。
八皇后问题有多少解
八皇后问题有多少解八皇后问题有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皇后同样的方法可以获得问题的解。
经典算法-(五)八皇后问题
经典算法-(五)⼋皇后问题简介:问题,是⼀个古⽼⽽著名的问题,是的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。
认为有76种⽅案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有⼈⽤图论的⽅法解出92种结果。
计算机发明后,有多种计算机语⾔可以解决此问题。
问题描述:⼋皇后问题是⼀个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置⼋个皇后,使得任何⼀个皇后都⽆法直接吃掉其他的皇后?为了达到此⽬的,任两个皇后都不能处于同⼀条横⾏、纵⾏或斜线上。
⼋皇后问题可以推⼴为更⼀般的n皇后摆放问题:这时棋盘的⼤⼩变为n1×n1,⽽皇后个数也变成n2。
⽽且仅当 n2 = 1 或 n1 ≥ 3 时问题有解。
java实现:public class Queen{//同栏是否有皇后,1表⽰有private int[] column;//右上⾄左下是否有皇后private int[] rup;//左上⾄右下是否有皇后private int[] lup;//解答private int[] queen;//解答编号private int num;public Queen(){column=new int[8+1];rup=new int[(2*8)+1];lup=new int[(2*8)+1];for(int i=1;i<=8;i++)column[i]=0;for(int i=1;i<=(2*8);i++)rup[i]=lup[i]=0; //初始定义全部⽆皇后queen=new int[8+1];}public void backtrack(int i){if(i>8){showAnswer();}else{for(int j=1;j<=8;j++){if((column[j]==0)&&(rup[i+j]==0)&&(lup[i-j+8]==0)){//这⾥右上到左下是左边开始数的,并且是从2开始计数的总共8个正好到9,⽽左上到右下是做右边开始数的所以开头是8.明显是从1开始计数的。
n皇后问题
n 后问题1 问题描述:N 皇后问题是一个古老而著名的问题。
该问题是十九世纪著名的数学家高斯1850年提出的。
八皇后问题要求在一个N *N 的棋盘上放上N 个皇后,使得每一个皇后既攻击不到另外N-1个皇后,也不被另外N-1个皇后所攻击.按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子,问有多少种不同的摆法?并找出所有的摆法。
因此,N 皇后问题等于要求N 个皇后中的任意两个不能被放在同一行或同一列或同一斜线上。
2 回朔法回溯法有“通用的题解法”之称。
从问题的某种可能情况出发,搜索所有能到达的可能情况,然后以其中一种可能的情况为新的出发点,继续向下探索,当所有可能情况1 2 3 4 5 6 7 8 1 2 3 4 5 6 78都探索过且都无法到达目标的时候,再回退到上一个出发点,继续探索另一个可能情况,这种不断回头寻找目标的方法称为“回溯法”。
适用于解组合是较大的问题。
回朔法思想:1针对所给问题,定义问题的解空间。
2.确定易于搜索的解空间结构。
3.以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
在搜索过程中,通常采用两种策略避免无效搜索:一是用约束函数剪去得不到可行解的子树;二是用限界函数剪去得不到最优解的子树。
这两类函数统称为剪枝函数。
回溯算法的一个显著的特性是在搜索过程中动态产生问题的解空间。
在任何时刻,只保存从根结点到当前扩展结点的路径。
因此,回溯算法的空间需求为o(n),(n为从根结点起最长路径的长度)。
而显式地存储整个解空间则需要o(2n)或o(n!)内存空间。
回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法。
void backtrack (int t){if (t>n) output(x);elsefor (int i=f(n,t);i<=g(n,t);i++){x[t]=h(i);if (constraint(t)&&bound(t)) backtrack(t+1);}}采用树的非递归深度优先遍历算法,可将回溯法表示为一个非递归迭代过程。
N皇后问题独立解算法研究和仿真实现
纪著名 的数学家 高斯 于 1 8 5 0年提 出: 在 8 * 8 格 的国际象棋上 摆放八个皇后 , 使其不能互相攻击 , 即任意两个皇后都不 能处
3 .独 立 解 概 念 独 立 解 是 指 考 虑 到 全 部 具 有 对 称 意 义 上 的解 后 只 保 留
义上对 称 的解后 , 我们猜 想 : 全 部可行 解和独 立解 之 间的 关
系约为 : 8 : 1 。 下面 以八 皇后 为例 判 断独 立解 , 如下 图 1 和图2 , 其 中 N 皇 后 问 题 的 解 有 七 种 对 称 关 系 ,分 别 是 :关 于 y = x对
称、 关于 x 轴对称 、 关于 Y 轴对称 、 关于 v = . X对称 、 顺旋 9 0 。 对 称、 逆旋 9 0 。 对称和顺旋( 逆旋) 1 8 0 。 对称 。由N皇 后的全部 可行解可得到 3种基本算子[ 1 ] 。 ( 1 1 主转置算 子: F 1 ( a l , a 2 , …, a n ) =( a ’ l , a ’ 2 , …, a ’ ) , 其中 a ’ i ( a i = k )
I l 学术探讨 篡莹研究
= = =: =: : . = = : =: =: =: =: : : =: : : == : = = ===: : : =: 一
l 2 0 1 3年 第 5耳 月
N皇后 问题 独 立解 算 法研 究和仿 真 实现
温 录亮 柯振钦 邹俊 飞
( 佛 山科 学技术学 院 计算 机系 , 广 东 佛 山 5 2 8 0 0 0 )
( k = 1 , 2 , …, n )
●
●
n皇后问题-分支限界法
一、问题11、问题描述一、N皇后问题在N*N的棋盘上放置彼此不受攻击的N个皇后。
按照国际象棋的规则,皇后可以攻击与之处于同一行或同一列或同一斜线上的棋子。
N皇后的问题等价于在N*N大小的棋盘中放置N个皇后,任何2个皇后都不放在同一行或同一列或同一斜线上。
使用队列式分支限界法,求出N个皇后的一种放置方案。
2、算法设计思想分支限界法解向量:因为皇后不能同行或同列,所以我们可以用这样一个解向量来表示问题的解X[x1,x2…xn] x=[1,2,3…n];表示1~n行皇后位于的列数解空间:因为皇后不能同行同列,因此解空间为排列树,使用广度优先搜索的方式搜索整棵树剪枝函数:判断新摆放的皇后是否在已经摆放的皇后的斜线上3、算法过程描述第一行第一列放置皇后,这个节点成为拓展节点,产生n-1个活结点,加入队列,第一行第二列到第n列分别产生n-1个活结点,加入队列,从队列取出第一个活结点,即第二行第二列,不满足剪枝函数的要求,除去这个节点,队列中的节点依次取出,满足剪枝函数的节点成为拓展节点产生活结点并加入队列,当成功进行到叶子节点时,就能得到问题的一个解,队列为空时,就得到了所有解4、算法实现及运行结果#include<iostream>#include<ctime>using namespace std;bool isOK(int n, int pieces[]){//剪枝函数//判断当前状态是否合理,即皇后会不会互相攻击for (int i = 1; i <= n-1; i++){for (int j = i + 1; j <= n; j++){int left = -(j - i);//向左的斜线int right = (j - i);//向右的斜线if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right){//第i行皇后和第j行皇后会互相攻击return false;}}}//所有皇后都不会互相攻击return true;}void swap(int &a, int &b){int t = a;a = b;b = t;}void nQueen(int n, int t, int pieces[]){if (t > n){for (int i = 1; i <= n; i++){for (int j = 1; j < pieces[i]; j++)cout << "- ";cout << pieces[i]<<" ";for (int j = pieces[i] + 1; j <= n; j++)cout << "- ";cout << endl;}cout << endl;}else{for (int i = t; i <= n; i++){swap(pieces[t], pieces[i]);if (isOK(t, pieces)){nQueen(n, t + 1, pieces);}swap(pieces[t], pieces[i]);}}}int main (){int n;cin >> n;int *pieces = new int[n + 1];for (int i = 1; i <= n; i++){pieces[i] = i;}nQueen(n, 1, pieces);cout << "OK" << endl;system("pause");}5、算法复杂度分析及算法改进子集树O(n^n)*剪枝函数(包括判断行列和斜线)O(n)=O(n^n+1)。
八皇后问题(N皇后问题)
⼋皇后问题(N皇后问题)⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。
⾸先来看看这张模拟⼋皇后的图。
这张图说明皇后具有横轴、竖轴以及两个斜轴⽅向的杀伤⼒,也就是像⽶字形⼀样;为了减少判断,我们按照⼀个⽅向往另⼀个⽅向排列,中间不能跳⾏,这样我们就可以只判断已经有皇后的位置,还没有皇后的就可以偷懒不⽤判断了。
我的⽅案是:1.从最下⾯开始排列,然后往上添加,从左往右排列,这样就只需要判断⽐⾃⼰Y坐标低的具有杀伤能⼒的位置有没有皇后就OK ⽅法是把⾃⼰假定要放置皇后的位置的X和Y轴都依据判断特性进⾏处理;例如,左斜线X和Y轴都减1;中间的只需要把Y 轴减1;右边的和左边的相反,X轴加1,Y轴减1;注意处理边界问题。
2.为了找到合适的位置我们需要在查找失败的时候具备回溯的能⼒,就需要退回到前⼀⾏(Y=Y-1,注意XY是否到边界),直⾄能回溯或者全部判断完毕,每次回溯的时候记得X轴要从头开始 3.通过⼀个数据结构记录正在查找的⽅案,通过另⼀个数据结构记录已经找到的⽅案,当然也可以⽤⼀个变量记录⽅案个数下⾯这张⿊⾊背景是其中⼀个⽅案的截图,第⼀⾏代表皇后的坐标xy;后⾯的是棋盘,这⾥输出竖轴是x,横轴是y,从上到下,从左到右,其中*是边界,空格是空区,#是皇后。
#include <iostream>#include <cstring>#include "DTString.h"#include "LinkList.h" // 这⾥使⽤链表存储皇后的位置using namespace std;using namespace DTLib;template <int SIZE> // N皇后问题,SIZE表⽰皇后个数或者棋盘⼤⼩class QueenSolution : public Object{protected:enum { N = SIZE + 2 }; // N表⽰棋盘⼤⼩,为了边界识别,棋盘四周都要加⼀格struct Pos : public Object // ⽅位结构体{Pos(int px = 0, int py = 0) : x(px), y(py) { }int x;int y;};int m_chessboard[N][N]; // 棋盘,0表⽰空位,1表⽰皇后,2表⽰边界Pos m_direction[3]; // 共3个⽅向;⽅向-1、-1表⽰左斜线;0、-1表⽰下⽅;1、-1表⽰右斜线;⾸先从最下⽅开始,所以只需考虑下⾯的⾏。
基本算法4-回溯法-N皇后问题
1
x1=1 2
x2= 2 3 kill
1
1 2
回溯到结点2生成结点8, 路径变为(1, 3), 则结点8成为E-结点, 它生成结点9和结点11都会被杀死(即它的儿子表示不可能导 x1=1 致答案的棋盘格局), 所以结点8也被杀死, 应回溯.
1
1
1
2
2
3
x2= 2 x2= 3 3 kill 8 x3=2 9 kill x3=4 11 kill
借书问题 [问题描述]
学校放暑假时,信息学辅导教师有n本书要分给参加培训的n个学生。如:A, B,C,D,E共5本书要分给参加培训的张、刘、王、李、孙5位学生,每人只能选 1本。教师事先让每个人将自己喜爱的书填写在如下的表中,然后根据他们填写的 表来分配书本,希望设计一个程序帮助教师求出可能的分配方案,使每个学生都满 意。 A 张 王 刘 孙 李 Y Y Y Y Y Y Y B C Y D Y E
● ●
……
● ● ● ● ● ● ● ●
……
……
●
●
●
●
●
● ● ● ●
●
●
● ●
●
● ●
●
● ●
● ● ● ●
● ● ● ●
● ● ● ●
● ● ● ● ●
● ● ●
•搜索解空间,剪枝:
– (1) 从空棋盘起,逐行放置棋子。
– (2) 每在一个布局中放下一个棋子,即推演到一 个新的布局。 – (3) 如果当前行上没有可合法放置棋子的位置, 则回溯到上一行,重新布放上一行的棋子。
61 2
64
3
16
3
20
4
22
1
25
n皇后问题解法总数 规律
n皇后问题解法总数规律
n皇后问题是指在一个n*n的棋盘上放置n个皇后,使任意两个皇后都不能相互攻击。
n皇后问题的解法总数可以用以下公式表示:C_{n,n-2}
其中,C是组合数,表示从n个元素中选择n-2个元素的组合数。
这个公式可以用以下方式推导:
假设我们已经将n-1个皇后放在了棋盘上,并且它们之间不会相互攻击。
那么,第n个皇后可以放在棋盘上的任何空位上,而不会与其他皇后相互攻击。
因此,第n个皇后的摆放方式有n种。
因此,n皇后问题的解法总数就是n-1个皇后的摆放方式总数乘以n,即:(n-1)C_{n-1}*n=C_{n,n-2}
●例如,2皇后问题的解法总数是:C_{2,0}=1
●3皇后问题的解法总数是:C_{3,1}=3
●4皇后问题的解法总数是:C_{4,2}=7
●5皇后问题的解法总数是:C_{5,3}=31
可以看到,n皇后问题的解法总数随着n的增加而呈指数增长。
八皇后问题详细的解法
1
1八皇后问题背景 2盲目的枚举算法 3加约束的枚举算法 4回溯法及基本思想 5 回溯法应用 6八皇后问题的递归回溯算法 7八皇后问题的非递归回溯算法
2
【背景】 八皇后问题是一个以国际象棋为背
景的问题: 如何能够在 8×8 的国际象棋棋盘上
放置八个皇后,使得任何一个皇后都 无法直接吃掉其他的皇后?为了达到 此目的,任两个皇后都不能处于同一 条横行、纵行或斜线上。
}
}
23
20
2 回溯法应用-算法框架-递归算法框架
int a[n]; Queens(int k) { if (k>n) 即表示最后一个皇后摆放完毕,输出结果;
else for(i=下界 ; i<=上界; i++) //枚举K个皇后所有可能的路径 {依次从列顶端开始搜索,一直到列底端,直到找到合适位置,如
果未找到,自动返回上层递归
的,能避免不必要搜索的穷举式搜索法。这种方法适 用于解一些组合数相当大的问题。 回溯法在问题的解空间树中,按深度优先策略,从根 结点出发搜索解空间树。算法搜索至解空间树的任意 一点时,先判断该结点是否包含问题的解。如果肯定 不包含,则跳过对该结点为根的子树的搜索,逐层向 其祖先结点回溯;否则,进入该子树,继续按深度优 先策略搜索。
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]); }
题,而不能解决任意
}}}}}}}
人工智能实验报告_八皇后问题
八皇后问题八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。
该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
基本思想:在open表中保留已生成而未考察的结点,并用启发函数h(x)对它们全部进行估价,从中选出最优结点进行扩展,而不管这个结点出现在搜索树的什么地方。
(1)把初始结点S0放入open表中,计算h(S0);(2)若open表为空,则搜索失败,EXIT;(3)移出open表中第一个结点N放入closed表中,并冠以序号n(4)若目标结点Sg=N则搜索成功,EXIT(5)若N不可扩展,则转步骤(2);(6)扩展N,计算每个子结点x的函数值h(x),并将所有子结点配以指向N的返回指针后放入open表中,再对open表中的所有子结点按其函数值大小以升序排序,转步骤2;//采用启发式修补解N皇后问题#include<time.h>#include <iostream>//采用启发式修补解N皇后问题#include<time.h>#include <iostream>using space std;void shuffle(int Queen[],const int n)...{//随机取得各行的初始皇后位置,以Queen[i]表示第i行的皇后位置for(int i=0;i<n;i )Queen[i]=abs(rand())%n;}int collision(int Queen[],const int row,const int column,const int n)...{ //计算每个位置的冲突值int bug=0;for(int i=0;i<n;i )...{if ((i!=row)&&(Queen[i]==column||(Queen[i]-column)==(i-row)||(Queen[i]-column)==(row-i)))//同列,同对角线的情况bug ;}return bug;}void show(int Queen[],const int n)...{//打印皇后图cout<<"╭";for(int k=0;k<n-1;k )cout<<"─┬";cout<<"─╮"<<endl;for(int i=0;i<n-1;i )...{cout<<"│";for(int j=0;j<n;j )cout<<((j==Queen[i])? "凤" :" ")<<"│";//有皇后的位置用"凤"cout<<endl;cout<<"├";for(j=0;j<n-1;j )cout<<"─┼";cout<<"─┤"<<endl;}cout<<"│";for(int j=0;j<n;j )cout<<((j==Queen[n-1])? "凤" :" ")<<"│";//有皇后的位置用,没有的用_ cout<<endl;cout<<"╰";for(k=0;k<n-1;k )cout<<"─┴";cout<<"─╯"<<endl;cout<<endl;}int repair(int Queen[],const int n)...{ //启发式修补int max=-1;//标志行行之间冲突数int minbug=n;int count=0;while(max!=0&&count<=100)...{max=0;for(int i=0;i<n;i )...{minbug=collision(Queen,i,Queen[i],n);//取得当前的冲突数,不断优化int temp=Queen[i];for(int j=0;j<n;j )...{int bug=collision(Queen,i,j,n);if(bug<=minbug&&j!=temp)...{ //保持皇后在等冲突的情况下不断变更位置,有利于后面行的优化minbug=bug;Queen[i]=j;}}if (minbug>max)max=minbug;}show(Queen,n);count ;}return count;}void main()...{int n=-1;int step=0;cout<<"Welcome to N Queen Settlement"<<endl;cout<<"Input N (you would better input a interge minor to 15):"<<endl;cin>>n;if(n<=0)...{cout<<"Illegal Input!"<<endl;return;}int* Queen=new int[n];srand(time(NULL));//取得随机种子shuffle(Queen,n);cout<<"The oringinal state:"<<endl;show(Queen,n);step=repair(Queen,n);if(step>100)...{cout<<"Could find solution within 100 steps,Try again!"<<endl;return;}cout<<"After "<<step 1<<" steps"<<endl;cout<<"The goal state arrives!"<<endl;}。
八皇后
,问题描述:八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
问题历史:八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔于1848年提出。
之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。
八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。
诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。
1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
转化规则:其实八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。
当且仅当n = 1 或n ≥ 4 时问题有解。
令一个一位数组a[n]保存所得解,其中a[i] 表示把第i个皇后放在第i行的列数(注意i的值都是从0开始计算的),下面就八皇后问题做一个简单的从规则到问题提取过程。
(1)因为所有的皇后都不能放在同一列,因此数组的不能存在相同的两个值。
(2)所有的皇后都不能在对角线上,那么该如何检测两个皇后是否在同一个对角线上?我们将棋盘的方格成一个二维数组,如下:。
回溯法实现8皇后问题
实验题目回溯法实现8皇后问题实验要求 a.掌握递归回溯算法的基本思想。
b.学习掌握应用面向对象通用回溯程序框架解决实际问题。
提高面向对象编程的技能。
实验内容(问题描述、算法设计、算法效率)回溯法实现8皇后问题a.问题描述:在n*n格的棋盘上放置彼此不受攻击的n个皇后。
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
N后问题等价于在n*n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
b.算法设计:用n元组x[1;n]表示n后问题的解。
其中,x[i]表示皇后i放置在棋盘的第i行的第x[i]列。
由于不容许将2个皇后放在同一列上,所以解向量中的x[i]互不相同。
2个皇后不能放在同一斜线上是问题的隐约束。
对于一般的n后问题,这一隐约束条件可以化成显约束的形式。
如果将n*n 格的棋盘看做二维方阵,其行号从上到下,列号从左到右依次编号为1,2,...n。
从棋盘左上角到右下角的主对角线及其平行线(即斜率为-1的各斜线)上,2个下标值的差(行号-列号)值相等。
同理,斜率为+1的每条斜线上,2个下标值的和(行号+列号)值相等。
因此,若2个皇后放置的位置分别是(i,j)和(k,l),且i-j = k -l 或i+j = k+l,则说明这2个皇后处于同一斜线上。
以上2个方程分别等价于i-k = j-l 和i-k =l-j。
由此可知,只要|i-k|=|l-j|成立,就表明2个皇后位于同一条斜线上。
用回溯法解n后问题,用完全n叉树表示解空间。
可行性约束Place剪去不满足行,列和斜线约束的子树。
下面的解n后问题的回溯法中,递归函数Backtrack(1)实现对整个解空间的回溯搜索。
Backtrack(i)搜索解空间中第i层子树。
类Queen的数据成员记录解空间中节点信息,以减少传给Backtrack的参数。
sum记录当前已找到的可行方案数。
在算法Backtrack中,当i>n是,算法搜索至叶节点,得到一个新的n皇后互不攻击放置方案,当前已找到的可行方案数sum增1。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
计算机发明后,有多种方法可以解决此问题。
请编程实现八皇后问题,并把92种解的前三种解输出到屏幕(8*8的二维矩阵,Q代表皇后,X代表空)。
并把此问题的求解过程延伸到N皇后问题。
程序代码如下所示:
package算法;
publicclass EightQueen{
private int index=1;
privatefinalstatic int SCALE=8;
private int[]answer=new int[SCALE];
private void initArray(){
for(int i=0;i<answer.length;i++){
answer[i]=-1;
}
}
private boolean canStay(int row,int col){
for(int i=0;i<row;i++)
{
if(answer[i]==col||Math.abs(row-i)==Math.abs(col-answer[i])) {
return false;
}
}
return true;
}
private void calculate(){
for(int row=0;row<SCALE;row++)
{
if(answer[row]==-1)
{
answer[row]=0;
}
for(int col=answer[row];col<=SCALE;col++)
{
if(col==SCALE)
{
answer[row]=-1;
row--;
if(row<0)
return;
}
col=answer[row];
continue;
}
if(canStay(row,col))
{
answer[row]=col;
if(row==SCALE-1)
{
showMsg();
continue;
}
break;
}
}
}
}
private void showMsg(){
if(index<4)
{
System.out.println(" - 第"+index+"种方案-"); for(int i=0;i<answer.length;i++)
for(int j=0;j<SCALE;j++)
{
if(answer[i]==j)
{
System.out.print("Q ");
}else{
System.out.print("X ");
}
}
System.out.println("");
}
System.out.println("\n");
index++;
}
}
public EightQueen(){
initArray();
calculate();
}
publicstatic void main(String[]args){
System.out.println("列举"+SCALE+"皇后问题的前3 种方案!"); System.out.println();
EightQueeneightQueen=new EightQueen();
}。