热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

八皇后问题学习笔记

1.问题描述:在nn的棋盘上放置n个不能互相捕捉的国际象棋“皇后”的所有布局。这是来源于国际象棋中的一个问题。皇后是棋盘上最具杀伤力的一个棋子,她可以捕

 1.       问题描述:

n×n的棋盘上放置n个不能互相捕捉的国际象棋“皇后”的所有布局。这是来源于国际象棋中的一个问题。皇后是棋盘上最具杀伤力的一个棋子,她可以捕捉与她在同一行,或同一列,或同一斜线(有两条)上的所有棋子。如下图所示,红线经过的格子都会被皇后捕捉。

 

 

2.       问题分析:

1)    皇后的杀伤力在她所对应的行,列,和两条斜线上,所以应该满足该皇后所在的行、列和两条斜线都不存在其它皇后。

2)    所以为了避免皇后冲突,一个可行的办法是将棋盘上所有的行,列,和斜线的占用状态分别用数组存起来,初始状态为未占用。在每成功放入一个皇后以后,将该皇后所对应的行,列,和两条斜线的状态更新为占用。在每次尝试将某个皇后放置到某个位置的时候,需要检查该位置所对应的行,列,和斜线的占用状态,只有全部未被占用,才可以将该皇后放到该位置。

3)    接下来的问题有两个:一是如何用数组来存储棋盘上所有的行,列,和斜线的占用状态?二是对棋盘上每一个位置如何找到它所对应的行、列和斜线在状态数组中的位置。以下分行、列、左低右高斜线和左高右低斜线四种情况来讨论:

4)    行:对n×n的棋盘有n行(1 ~ n),用一个n + 1维的数组row[n + 1](row[0]不用)来表示每一行的占用状态。位置(i,j)对应的行的占用状态为row[i]

5)    列:对n×n的棋盘有n列(1 ~ n),用一个n + 1维的数组col[n + 1](col[0]不用)来表示每一列的占用状态。位置(i,j)对应的列的占用状态为col[j]

6)    左低右高斜线:n×n的棋盘总共有2n – 1条左低右高斜线,所以可以用2n维的数组b[2n](b[0]不用)来存储每一条左低右高斜线的占用状态。。对某一条斜线,其特点是它所经过的每一个格子的(列号 + 行号)相等,所以可以用这个值作为数组下标来唯一标记每一条左低右高斜线,为了使下标从1开始,对所有的下标减1。如下图所示。位置(i,j)对应的左低右高斜线的占用状态为b[i + j – 1]

 

7)    左高右低斜线:n×n的棋盘总共有2n – 1条左高右低斜线,所以可以用2n维的数组c[2n](c[0]不用)来存储每一条左高右低斜线的占用状态。。对某一条斜线,其特点是它所经过的每一个格子的(列号 行号)相等,所以可以用这个值作为数组下标来唯一标记每一条左高右低斜线,为了避免出现负值,将所有的下标值都加上一个n。如下图所示。位置(i,j)对应的左高右低斜线的占用状态为c[n + j - i]

 

 

3.       解题思路:

1)    要将n个皇后放到n×n的棋盘中,则每一列必须且只能放一个皇后。所以问题转化为确定皇后在每一列中的位置(在第几行上)。

2)    从第一列开始,依次考察每一列。

3)    在考察每一列的时候,总是从第一行开始,尝试将皇后放入,如果可以放入,就接着考察下一列的第一行。如果不可以放入,就接着考察这一列的下一行,直到成功,然后接着考察下一列的第一行。

4)    如果这一列的每一行都不可以放入,说明这一列前面各列的皇后放置有问题,导致这一列无法放入,需要回溯。

5)    回溯的时候,如果前面的一列每一行都已经被尝试过了,就需要接着往前回溯,直到找到还有行未被尝试过的列,然后尝试这一列的下一行。

6)    在回溯过程中经过的每一列都需要将已经放入的皇后取出来,以备后面重新选择位置放入。

7)    如果每一列都被考察完毕,即每一列中的皇后都找到了合适的位置,则找到一个解。

8)    在找到一个解后,如果还要寻找其它解,则需要回溯,尝试其它情况。

9)    当回溯到第0列时,说明1 ~ n列的所有行都已经被尝试过了,没有其它情况可以尝试,结束程序。

  

4.       代码:

ContractedBlock.gifExpandedBlockStart.gifCode
void QueenLayout(int n)
{
    
int j;
    
char next;    
    
int* row = new int[n + 1]; //每一行的状态(是否已经被占用:0 - 未被占用,1 - 被占用)。
    int* col = new int[n + 1]; //皇后在每一列中的位置(行号)
    int* b = new int[2 * n]; //每一条正斜线(左低右高)的状态(是否已经被占用:0 - 未被占用,1 - 被占用)。
    int* c = new int[2 * n]; //每一条反斜线(左高右低)的状态(是否已经被占用:0 - 未被占用,1 - 被占用)。    
    bool occupied = false//用于判断在每一列中放置皇后时,她所对应的行和两条斜线,是否至少有一条已经被占用。

    
int m = 1//当前被考察的列
    col[0= col[1= 1//从第一列开始的第一行开始考察,如果可以就考察第二列的第一行,如果不可以就考察第一列的第二行(即col[1] = 2)

    
//初始化所有的行为未被占用状态
    for (j &#61; 0; j <&#61; n; j&#43;&#43;)
    {
        row[j] 
&#61; 0;
    }

    
//初始化所有的斜线为未被占用状态
    for (j &#61; 0; j < 2*n; j&#43;&#43;)
    {
        b[j] 
&#61; c[j] &#61; 0;
    }

    
do
    {
        
if (!occupied)
        {
            
//已经考察到第n列&#xff0c;所以一次考察完毕。
            if (m &#61;&#61; n)
            {
                
//打印找到的一个解
                cout << "Column\tRow\n";
                
for (j &#61; 1; j <&#61; n; j&#43;&#43;)
                {
                    printf(
"%3d\t%d\n", j, col[j]);
                }

                
//是否接着寻找下一个解
                cout << "Find next solution? (Y/N)\n";
                cin 
>> next;
                
if (next !&#61; &#39;Y&#39; && next !&#61; &#39;y&#39;)
                {
                    
return;
                }

                
//已经找到一个解&#xff0c;回溯找下一个解。
                
//一直回溯到还有行未被考察过的列
                while(col[m] &#61;&#61; n)
                {
                    m
--;
                    
//在回溯过程中经过的每一列都需要将已经放入的皇后取出来&#xff0c;以备后面重新选择位置放入。
                    row[col[m]] &#61; b[m &#43; col[m] - 1&#61; c[n &#43; m - col[m]] &#61; 0;
                }
                
//考察这一列的下一行
                col[m]&#43;&#43;;
            }
            
else
            {
                
//因为occupied&#61;&#61;false&#xff0c;所以皇后可以被放在当前考察列的当前考察行
                
//将该皇后对应的行和两条斜线置为被占用状态
                row[col[m]]&#61;b[m &#43; col[m] - 1&#61; c[n &#43; m - col[m]] &#61; 1;
                
//考察下一列的第一行
                col[&#43;&#43;m] &#61; 1;
            }
        }
        
else
        {
            
//因为occupied&#61;&#61;true&#xff0c;所以皇后不可以被放在当前考察列的当前考察行
            
//一直回溯到还有行未被考察过的列
            while(col[m] &#61;&#61; n)
            {
                m
--;
                
//在回溯过程中经过的每一列都需要将已经放入的皇后取出来&#xff0c;以备后面重新选择位置放入。
                row[col[m]] &#61; b[m&#43;col[m] - 1&#61; c[n &#43; m - col[m]] &#61; 0;
            }
            
//考察这一列的下一行
            col[m]&#43;&#43;;
        }
        
//考察皇后是否可以被放在当前考察列的当前考察行&#xff0c;即她对应的行和两条斜线是否全部未被占用
        occupied &#61; row[col[m]] || b[m &#43; col[m] - 1|| c[n &#43; m -col[m]];
    }
while (m !&#61; 0);//退到m &#61;&#61; 0, 表示 1 ~ n 列的所有行都被考察过了&#xff0c;即考察过了所有可能的情况&#xff0c;整个考察过程结束。

    delete []row;
    delete []col;
    delete []b;
    delete []c;    
}

 

转:https://www.cnblogs.com/zsh_robot/articles/1320075.html



推荐阅读
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java图形化计算器设计与实现
    本文介绍了使用Java编程语言设计和实现图形化计算器的方法。通过使用swing包和awt包中的组件,作者创建了一个具有按钮监听器和自定义界面尺寸和布局的计算器。文章还分享了在图形化界面设计中的一些心得体会。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 今日份分享:Flutter自定义之旋转木马
    今日份分享:Flutter自定义之旋转木马-先上图,带你回到童年时光:效果分析子布局按照圆形顺序放置且平分角度子布局旋转、支持手势滑动旋转、快速滑动抬手继续旋转、自动旋转支持X轴旋 ... [详细]
author-avatar
南方的狼1975
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有