[解题报告]POJ-2698-八皇后问题

本文深入解析八皇后问题的解题思路与算法实现,通过深度搜索加记忆数组的方法解决皇后不能互相攻击的问题,并提供简化版代码与直接交表两种解法。详细阐述了如何使用记忆数组判断列、主对角线与副对角线的状态,确保八个皇后在国际象棋棋盘上的合理布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目
2698:八皇后问题

原题链接:http://poj.grids.cn/practice/2698/

时间限制: 10000ms 内存限制: 65536kB
描述
在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。
输入
无输入。
输出
按给定顺序和格式输出所有八皇后问题的解(见Sample Output)。
样例输入
样例输出
No. 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 
 No. 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 
 No. 3 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 
 No. 4 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 
 No. 5 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 
 No. 6 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 
 No. 7 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 
 No. 8 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 
 No. 9 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 ...
以下省略...
提示  此题可使用函数递归调用的方法求解。
二、分析   
  1、递归法;2、交表法
八皇后问题经典解析:

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使 其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种方法可 以解决此问题。

摘自百度百科
解题思路:深度搜索加记忆数组
*因为皇后不能处于同一行,同一列,同一斜线(即主对角线和副对角线),所以可以判断出8个皇后分别各占一行
*不妨假设从第一行开始,行数依次加一确定每一行皇后的位置,在下面的程序中cur代表行号,因为我们依次让
*行号加一,所以不会存在行号重叠的现象,接下来只需判断列数和对角线没有发生重叠即可,这里,我们用一个记
*忆状态的数组(vis[][])来存储列和对角线的状态,每次确定一个皇后的位置,首先判断其对应的列和对角线是否
*染色,如果没有染色,则该位置有效,并染色,这样就不会出现列和对角线重叠的问题.
下面重点讲解一下对角线,其原理可用下图说明:

 (格子(i-j)的值标示了主对角线)
同理读者自行可以推出
 (格子(i+j)的值标示了副对角线)
又因为主对角线的值有为负数的情况,所以我们在标记的时候应该加>=7的数,所有值都加了>=7所以标记的效果并没有改变

简化版代码:
1 #include<iostream>
2 using namespace std;
3 bool vis[ 3][ 30]; // 记忆数组判断列,主对角线,副对角线是否被占
4 int ans= 0;
5 void dfs( int cur)
6 {
7 if(cur== 9) // 如果当前行数超过8(表明八个皇后已经放好)则结果加一,返回继续递归
8 {
9 ans++;
10 return ;
11 }
12 // vis[0][i]判断列,vis[i][cur-i+8]判断主对角线,vis[2][cur+i]判断副对角线
13 for( int i= 1;i<= 8;i++) if(!vis[ 0][i]&&!vis[ 1][cur-i+ 8]&&!vis[ 2][cur+i])
14 {
15 vis[ 0][i]=vis[ 1][cur-i+ 8]=vis[ 2][cur+i]= true;
16 dfs(cur+ 1); // 深度搜索
17 vis[ 0][i]=vis[ 1][cur-i+ 8]=vis[ 2][cur+i]= false;
18 }
19 }
20 int main()
21 {
22 dfs( 1); // 初始化cur为1,即从第一行开始
23 cout<< " "<<ans<< " 种结果. "<<endl;
24 system( " pause ");
25 return 0;
26 }
三、AC源代码
1、递归求解
1 #include<iostream>
2 using namespace std;
3
4 bool vis[ 3][ 20]; // 记忆数组判断列,主对角线,副对角线是否被占
5 int ans= 0,num= 1;
6 int p= 0,pos[ 8];
7
8 void dfs( int cur);
9 void print();
10
11 int main()
12 {
13 dfs( 1); // 初始化cur为0,即从第一行开始
14 return 0;
15 }
16
17 void dfs( int cur)
18 {
19 if(cur> 8) // 如果当前行数超过8(表明八个皇后已经放好)则结果加一,返回继续递归
20 {
21 ans++;
22 print();
23 return;
24 }
25 // vis[0][i]判断列,vis[i][cur-i+8]判断主对角线,vis[2][cur+i]判断副对角线
26 for( int i= 1;i<= 8;i++)
27 if(!vis[ 0][i]&&!vis[ 1][cur-i+ 8]&&!vis[ 2][cur+i])
28 {
29 pos[p++]=i;
30 vis[ 0][i]=vis[ 1][cur-i+ 8]=vis[ 2][cur+i]= true;
31 dfs(cur+ 1); // 深度搜索
32 vis[ 0][i]=vis[ 1][cur-i+ 8]=vis[ 2][cur+i]= false;
33 p--;
34 }
35 }
36
37 void print()
38 {
39 int i,j;
40 cout<< " No. "<<num++<<endl;
41 for(i= 0;i< 8;i++)
42 {
43 for(j= 0;j< 8;j++)
44 if(i==pos[j]- 1)
45 cout<< " 1 ";
46 else
47 cout<< " 0 ";
48 cout<<endl;
49 }
50 /* for(i=0;i<8;i++)
51 cout<<pos[i];
52 cout<<endl; */
53 }
2、直接交表
1 #include <stdio.h>
2 int pos[ 736]={ 1, 5, 8, 6, 3, 7, 2, 4, 1, 6, 8, 3, 7, 4, 2, 5, 1, 7, 4, 6, 8, 2, 5, 3, 1, 7, 5, 8, 2, 4, 6, 3, 2, 4, 6, 8, 3, 1, 7, 5, 2, 5, 7, 1, 3, 8, 6, 4, 2, 5, 7, 4, 1, 8, 6, 3, 2, 6, 1, 7, 4, 8, 3, 5, 2, 6, 8, 3, 1, 4, 7, 5, 2, 7, 3, 6, 8, 5, 1, 4, 2, 7, 5, 8, 1, 4, 6, 3, 2, 8, 6, 1, 3, 5, 7, 4, 3, 1, 7, 5, 8, 2, 4, 6, 3, 5, 2, 8, 1, 7, 4, 6, 3, 5, 2, 8, 6, 4, 7, 1, 3, 5, 7, 1, 4, 2, 8, 6, 3, 5, 8, 4, 1, 7, 2, 6, 3, 6, 2, 5, 8, 1, 7, 4, 3, 6, 2, 7, 1, 4, 8, 5, 3, 6, 2, 7, 5, 1, 8, 4, 3, 6, 4, 1, 8, 5, 7, 2, 3, 6, 4, 2, 8, 5, 7, 1, 3, 6, 8, 1, 4, 7, 5, 2, 3, 6, 8, 1, 5, 7, 2, 4, 3, 6, 8, 2, 4, 1, 7, 5, 3, 7, 2, 8, 5, 1, 4, 6, 3, 7, 2, 8, 6, 4, 1, 5, 3, 8, 4, 7, 1, 6, 2, 5, 4, 1, 5, 8, 2, 7, 3, 6, 4, 1, 5, 8, 6, 3, 7, 2, 4, 2, 5, 8, 6, 1, 3, 7, 4, 2, 7, 3, 6, 8, 1, 5, 4, 2, 7, 3, 6, 8, 5, 1, 4, 2, 7, 5, 1, 8, 6, 3, 4, 2, 8, 5, 7, 1, 3, 6, 4, 2, 8, 6, 1, 3, 5, 7, 4, 6, 1, 5, 2, 8, 3, 7, 4, 6, 8, 2, 7, 1, 3, 5, 4, 6, 8, 3, 1, 7, 5, 2, 4, 7, 1, 8, 5, 2, 6, 3, 4, 7, 3, 8, 2, 5, 1, 6, 4, 7, 5, 2, 6, 1, 3, 8, 4, 7, 5, 3, 1, 6, 8, 2, 4, 8, 1, 3, 6, 2, 7, 5, 4, 8, 1, 5, 7, 2, 6, 3, 4, 8, 5, 3, 1, 7, 2, 6, 5, 1, 4, 6, 8, 2, 7, 3, 5, 1, 8, 4, 2, 7, 3, 6, 5, 1, 8, 6, 3, 7, 2, 4, 5, 2, 4, 6, 8, 3, 1, 7, 5, 2, 4, 7, 3, 8, 6, 1, 5, 2, 6, 1, 7, 4, 8, 3, 5, 2, 8, 1, 4, 7, 3, 6, 5, 3, 1, 6, 8, 2, 4, 7, 5, 3, 1, 7, 2, 8, 6, 4, 5, 3, 8, 4, 7, 1, 6, 2, 5, 7, 1, 3, 8, 6, 4, 2, 5, 7, 1, 4, 2, 8, 6, 3, 5, 7, 2, 4, 8, 1, 3, 6, 5, 7, 2, 6, 3, 1, 4, 8, 5, 7, 2, 6, 3, 1, 8, 4, 5, 7, 4, 1, 3, 8, 6, 2, 5, 8, 4, 1, 3, 6, 2, 7, 5, 8, 4, 1, 7, 2, 6, 3, 6, 1, 5, 2, 8, 3, 7, 4, 6, 2, 7, 1, 3, 5, 8, 4, 6, 2, 7, 1, 4, 8, 5, 3, 6, 3, 1, 7, 5, 8, 2, 4, 6, 3, 1, 8, 4, 2, 7, 5, 6, 3, 1, 8, 5, 2, 4, 7, 6, 3, 5, 7, 1, 4, 2, 8, 6, 3, 5, 8, 1, 4, 2, 7, 6, 3, 7, 2, 4, 8, 1, 5, 6, 3, 7, 2, 8, 5, 1, 4, 6, 3, 7, 4, 1, 8, 2, 5, 6, 4, 1, 5, 8, 2, 7, 3, 6, 4, 2, 8, 5, 7, 1, 3, 6, 4, 7, 1, 3, 5, 2, 8, 6, 4, 7, 1, 8, 2, 5, 3, 6, 8, 2, 4, 1, 7, 5, 3, 7, 1, 3, 8, 6, 4, 2, 5, 7, 2, 4, 1, 8, 5, 3, 6, 7, 2, 6, 3, 1, 4, 8, 5, 7, 3, 1, 6, 8, 5, 2, 4, 7, 3, 8, 2, 5, 1, 6, 4, 7, 4, 2, 5, 8, 1, 3, 6, 7, 4, 2, 8, 6, 1, 3, 5, 7, 5, 3, 1, 6, 8, 2, 4, 8, 2, 4, 1, 7, 5, 3, 6, 8, 2, 5, 3, 1, 7, 4, 6, 8, 3, 1, 6, 2, 5, 7, 4, 8, 4, 1, 3, 6, 2, 7, 5};
3 int main()
4 {
5 int i,j,n= 92;
6 while(n--)
7 {
8 printf( " No. %d\n ", 92-n);
9 for(i= 0;i< 8;i++)
10 {
11 for(j= 0;j< 8;j++)
12 if(i==pos[( 91-n)* 8+j]- 1)
13 printf( " 1 ");
14 else
15 printf( " 0 ");
16 printf( " \n ");
17 }
18 }
19 return 0;
20 }




<script>window._bd_share_config={"common":{"bdsnskey":{},"bdtext":"","bdmini":"2","bdminilist":false,"bdpic":"","bdstyle":"0","bdsize":"16"},"share":{}};with(document)0[(getelementsbytagname('head')[0]||body).appendchild(createelement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new date()/36e5)];</script>
阅读(1265) | 评论(0) | 转发(0) |
0

上一篇:程序员必看

下一篇:八皇后

给主人留下些什么吧!~~
评论热议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zheguangqi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值