r语言 第n行第n列_算法设计:回溯法-n皇后问题

N皇后问题

一、问题描述

在N X N的棋盘放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之在同一行、同一列、同一斜线上的棋子。设计算法在N X N 的棋盘上放置n个皇后,使其彼此不受攻击

eec13bf6a6025a0feffecfd63d1ab10c.png

二、问题分析

棋盘如图所示,我们在第i行第j列放置一个皇后,那么第i行的其它位置(同行),那么第j列的其它位置(同列),同一斜线上的其它位置,都不能放置皇后

条件是这样要求的,但是我们不可能杂乱无章的尝试每个位置,要有求解策略。我们可以以行为主导:

(1)在第1行第1列放置第1个皇后

(2)在第2行放置第2个皇后。第2个皇后的位置不能和第1个皇后同列、同斜线,不用再判断是否同行了

(3)在第3行放置第3个皇后,第3个皇后的位置不能和前2个皇后同列、同斜线

(4)在第t行放置第t个皇后,第t个皇后的位置不能和前t-1个皇后同列、同斜线

(5)在第n行放置第n个皇后,第n个皇后的位置不能和前n-1个皇后同列、同斜线

26a2b9440e39441678802b8e99649cd9.png

三、算法设计

1、定义解空间

N皇后问题的解形式为n元组:{x1 , x2,x3,…..,xi,…..xn},分量xi表示第i个皇后放置在第i行第xi列,xi的取值为1,2,3,….,n。例如:x2 = 5表示第2个皇后放置在第2行第5列。显约束为不同行

2、解空间的组织结构

N皇后解空间是一个m(m = n)叉树,数的深度为n

57adc17eb61c8a95f6f1b894f93e8826.png

3、搜索解空间

(1)约束条件

在第t行放置第t个皇后时,第t个皇后的位置不能和前t-1个皇后同列、同斜线。第i个皇后和第j个皇后不同列,即xi ! = xj,并且不同斜线,即 | i – j | ! = | xi – xj |

(2)限界条件

该问题不存在放置方案好坏情况,所以不需要设置限界条件

(3)搜索过程

从根开始,以深度优先搜索的方式进行搜索。根节点是活节点,并且是当前的扩展节点。在搜索过程中,当前的扩展节点沿着纵深方向移向一个新节点,判断该节点是否满足隐约束。如果满足,则新节点成为活节点,并且称为当前的扩展节点,继续深一层的搜索;如果不满足,则换到该新节点的兄弟节点继续搜索;如果新节点没有兄弟节点,或其兄弟节点已经全部搜索完毕,则扩展节点称为死节点,搜索回溯到其父节点处继续进行。搜索过程直到找到问题的根节点变成死节点为止

4、算法图解

为了说明问题,我们在4x4的棋盘上放置4个皇后,使其彼此不受攻击

a1771cefe147cdb38e65620f3ef94ff1.png

(1) 开始搜索第1层(t = 1)

扩展1号节点,首先判断x1 = 1是否满足约束条件,因为之前还未选中任何节点,满足约束条件。令 x[1] = 1 ,生成2号节点

ef386e11a073f7fc88982d7ab70ca6f3.png

(2)扩展2号节点(t = 2)

首先判断x2=1不满足约束条件,因为和之前放置的第1个皇后同列;考查x2 = 2也不满足约束条件,因为和之前放置的第1个皇后同斜线;考查x2 =3满足约束条件,和之前放置的皇后不同列、不同斜线,令x[2] = 3,生成3号节点

0fbeffcd1400efdab8017dbb3c61fc3a.png

(3)扩展3号节点

首先判断x3=1不满足约束条件,因为和之前放置的第1个皇后同列;考查x2 = 2也不满足约束条件,因为和之前放置的第2个皇后同斜线;考查x3 =3不满足约束条件,因为和之前放置的第2个皇后同列;考查x3=4也不满足条件,因为和之前放置的第2个皇后同斜线;3号节点所有的孩子都已经考查完毕,3号节点成为死节点,向上回溯到2号节点

683f0ed140c878759aac1facb19ef31d.png

(4)重新扩展2号节点( t = 2)

判断x = 4满足约束条件,因为和之前放置的第1个皇后不同列、不同斜线,领x[2] = 4,生产4号节点,如图:

29fb7ab9feacc1a825647312333cd1d6.png

(5)扩展4号节点 ( t =3 )

首先判断x3=1不满足条件,因为之前放置的第1个皇后同列;考查x3=2满足约束条件,因为和之前放置的第1、2个皇后不同列、不同斜线令x[3]=2,生成5号节点,如图:

65dca52c0a7e4963de193ad1f5d0b7d6.png

(6)扩展5号节点( t =4 )

首先判断x4=1不满足约束条件,因为和之前放置的第1个皇后同列;考查x4=2也不满足约束条件,因为和之前放置的第3个皇后同列;考查x4=3不满足约束条件,因为和之前放置的第3个皇后同斜线;考查x4=4也不满足约束条件,因为和之前放置的第2个皇后同列;5号节点所有孩子均已考查完毕,5号节点成为死节点,向上回溯到4号节点

2dc2f3897f1bc617a0cd4b6e69302578.png

(7)继续扩展4号节点( t = 3)

判断x3=3不满足约束条件,因为和之前放置的第2个皇后同斜线;考查x3=4也不满足约束条件,因为和之前放置的第2个皇后同列。4号节点所有孩子均已考查完毕,4号节点成为死节点。向上回溯到2号节点,2号节点所有孩子节点均已经考查完毕,2号节点成为死节点,向上回溯到1号节点

7e1557f901056c5f79bd44258500c735.png

(8)继续扩展1号节点(t=1)

判断x1=2是否满足约束条件,因为之前还未选中任何节点,满足约束条件。令x[1]=2,生成6号节点,如图:

5c065ea2adfdefd82590264b116d7ac5.png

(9)扩展6号节点(t=2)

判断x2=1不满足约束条件,因为和之前放置的第1个皇后同斜线;考查x2=2也不满足约束条件,因为和之前放置的第1个皇后同列;考查x2=3不满足约束条件,因为和之前放置的第1个皇后同斜线;考查x2=4满足约束条件,令x[2] = 4,生成7号节点

f7a2d67f0c3adc9ba714a3cf7272bb48.png

(10)扩展7号节点(t=3)

判断x3=1满足约束条件,因为和之前放置的第1、2个皇后不同列、不同斜线,令x[3]=1,生成8号节点,如图:

d6411c5e884cb4f2c3ce045018e77e39.png

(11)扩展8号节点(t=4)

判断x4=1不满足约束条件,因为和之前放置的第3个皇后同列。

。。。

考查x4=3满足约束条件,令x[4] = 3生成9号节点,如图:

6095c85294d0c29ec719e7f8bd9c9e25.png

(12)扩展9号节点(t=5)

t > n找到一个可行解。用bestx[]保存当前可行解{2,4,1,3} 。9号节点成为死节点,向上回溯到8号节点

(13)继续扩展8号节点(t=4)

判断x=4不满足约束条件。至此8号节点考查完毕,成为死节点。向上回溯到7号节点

(14)继续扩展7号节点(t=3)

判断x3=2不满足;x3=3不满足;x3=4不满足。所有节点考查完毕,7号节点为死节点。向上回溯到6号节点,6号节点所有孩子考查完毕,成为死结点,向上回溯到1号节点,如图:

2e3f28ad567a43bd1a7790d9d2da7f2c.png

(15)继续扩展1号节点(t=1)

判断x1=3满足约束条件,令x[1]=3生成10号节点

4c235df979056741403bb117f43b058b.png

(16)扩展10号节点(t=2)

首先判断x2=1满足约束条件;令x[2] =1生成11号节点

4369db90a37d9e621bbbfa8c318c650a.png

(17)扩展11号节点

判断x3=1不满足;x3=2不满足;x3=3不满足。X3=4满足条件,令x[3]=4,生成12号节点,如图:

72d0211346b966fb78acb6ead1772bac.png

(18)扩展12号节点(t=4)

判断x4=1不满足约束条件;x4=2满足约束,令x[4]=2,生成13号节点

42af975cc79ddc7f3516b617e4035e20.png

(19)扩展13号节点(t=5)

t>n,找到一个可行解,用bestx[]保存当前可行解{3,1,4,2}。13号节点为死节点,向上回溯到12号节点

(20)继续扩展12号节点(t=4)

判断x4=3不满足;x4=4不满足;12号节点为死节点。向上回溯到11号节点。11号节点所有孩子均已经考查,成为死节点。再向上回溯到10号节点

(21)继续扩展10号节点(t=2)

判断x2=2不满足;判断x2=3不满足;判断x2=4不满足;10号节点为死节点。向上回溯到1号节点

(

7f35a907caae5eebc0a7d20d44e6587f.png

(22)继续扩展1号节点(t=1)

判断x1=4是否满足,因为之前无任何节点,所以满足。令x[1]=4,生成14号节点,如图:

d39b1bc35611f645630d8942096b4e09.png

(23)扩展14号节点(t=2)

首先判断x2=1满足约束条件,令x[2]=1,生成15号节点,如图:

49400c8bc936ff5ed14e51b64d36bd61.png

(24)扩展15号节点(t=3)

判断x3=1不满足;x3=2不满足;x3=3满足条件。令x[3]=3,生成16号节点,如图:

bf746fc60ddfe30c236e7a6d980cd058.png

(25)扩展16号节点(t=4)

首先判断x4=1不满足;x4=2不满足;x4=3不满足;x4=4不满足,16号节点为死节点,向上回溯到15号节点

(26)继续扩展15号节点(t=3)

判断x3=4不满足约束条件;15号考查完毕为死节点;向上回溯到14号节点

(27)继续扩展14号节点(t=2)

判断x2=2满足,令x[2]=2,生成17号节点:

b959e617825168c71b507d9825c4df8d.png

(28)扩展17号节点(t=3)

判断x3=1不满足;x3=2不满足;x3=3不满足;x3=4不满足。17号考查完毕,成为死节点,向上回溯到14号节点

(29)继续扩展14号节点(t=2)

判断x2=3不满足;x2=4不满足。14号考查完毕,回溯到1号节点

(30)1号所有均已经考查完毕,都是死节点。算法结束,如图:

10dcb60ba680eb3cbf2d2ae0e438914f.png

5、伪代码详解

(1)约束函数

在第t行放置第t个皇后的时候,第t个皇后与前t-1个已经放置好的皇后不能再同一列或者同一斜线,如果有一个成立,则第t个皇后不可以放置在该位置

X[t] == x[j] 表示第t个皇后和第j个皇后位置在同一列,t-j==fabs(x[t]-x[j])表示第t个皇后和第j个皇后位置在同一斜线。fabs是求绝对值,使用该函数要引入头文件#include

//判断第t个皇后是否能放在第i个位置

bool place(int t)

{

bool ok = true;

//判断该位置的皇后是否与前面t-1个已经放置好的皇后冲突

for( int j = 1 ; j < t ; j ++)

{

//判断同列、对角线是否冲突

if (x[t] == x[j] || t – j == fabs( x[t] – x[j] ) )

{

ok = false;

break;

}

}

return ok;

}

(2)按照约束条件搜索求解

t表示当前扩展节点在第t层。如果r > n,表示已经到达叶子节点,记录最优值和最优解,返回。否则,分别判断 n (i = 1,….,n)个分支,x[t] =i ;判断每个分支是否满足约束条件,如果满足则进入下一层backTrack(t+1);如果不满足则考查下一个分支(兄弟节点)

void backTrack(int t)

{

//如果当前位置为n,则表示已经找到问题的一个解

If( t > n)

{

Count + +;

//打印选择的路径

For(int I = 1; i<=n ;i++)

{

Cout<

Cout<

Cout<

}

}else{

//分别判断n个分支,特别注意i不要定义为全局变量,否则递归调用有问题

For(int I = 1; i<=n ; i++){

x[t] = i;

//如果不冲突的话进行下一行搜索

If( place(t) ){

backTrack(t+1);

}

}

}

}

6、代码实现:

#include

#include

#define M 105

using namespace std;

int n=4;//4个皇后

int x[M];//x[i]表示第i个皇后放在第i行第x[i]列

int countn;//表示n个皇后可行解的个数

bool place(int t){

bool ok = true;

//判断该位置的皇后是否与前面t-1个已经放置的皇后冲突

for(int j=1; j

//判断列、对角线是否冲突

if(x[t] == x[j] || t-j == fabs(x[t]-x[j])){

ok=false;

break;

}

}

return ok;

}

void backTrack(int t){

//如果当前位置为n,则表示已经找到了问题的一个解

if(t > n){

countn++;

//打印选择的路径

for(int i=1;i<=n;i++){

printf("%d",x[i]);

printf(" ");

}

}else{

//分别判断n个分支,特别注意i不要定义为全局变量,否则递归调用有问题

for(int i = 1 ;i<=n;i++){

x[t]=i;

if(place(t)){

//如果不冲突的话进行下一行的搜索

backTrack(t+1);

}

}

}

}

int main()

{

countn=0;

backTrack(1);

cout << "解个数" <

return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值