N皇后问题实验报告

时间:2024.4.20

一、    实验内容

在n×n格的棋盘上放置彼此不受攻击的n个皇后,按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子,求解可以放置的方法种数。

二、     问题分析

n后问题等于于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。即规定每一列放一个皇后,不会造成列上的冲突;当第i行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以i为下标的标记置为被占领状态。

三、    算法设计   

1.   解决冲突问题:

这个问题包括了行,列,两条对角线;

列:规定每一列放一个皇后,不会造成列上的冲突;

行:当第i行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以i为下标的标记置为被占领状态;

对角线:对角线有两个方向。在这我把这两条对角线称为:主对角线和从对角线。在同一对角线上的所有点(设下标为(i,j)),要么(i+j)是常数,要么(i-j)是常数。因此,当第i个皇后占领了第j列后,要同时把以(i+j)、(i-j)为下标的标记置为被占领状态。

2.   算法设计

因为n皇后问题,从n大于11开始求解过程耗时就很长,所以定义x数组的最大值MAXNUM=30;即最大可解决30皇后问题。

1)    判断当前位置是否可放置皇后

皇后k在第k行第x[k]列时,x[i]==x[k] 时,两皇后在同一列上;abs(x[i]-x[k])==abs(i-k)时,两皇后在同一斜线上;两种情况两皇后都可相互攻击,返回false表示不符合条件。

bool Place(int k)

{

     int i;

     i=1;

     while(i<k)

     {

     if(x[i]==x[k]||abs(x[i]-x[k])==abs(i-k))

                return false;

          i=i+1;

     }

     return true;

2)    输出当前解

void Print(int x[],int n)

{

     num++;

     printf("第%d\t种解法:(",num);

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

     {

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

          if(i%n==0)printf(");\n");

     }

3)    回溯法搜索解空间

void NQueens(int n)

{

     int k=1;

     x[1]=0;

     while(k>0)

     {

          x[k]+=1;

          while(x[k]<=n&&!Place(k))

                x[k]+=1;

          if(x[k]<=n)

          {

                if(k==n)

                      Print(x,n);

                else

                {

                      k=k+1;

                      x[k]=0;

                }

          }

          //回溯至上一行;

          else

                k--;

     }

}

3.   实验结果及分析

n皇后问题解的情况

4.    实验程序

随着N 的增大,解的个数增多,以N=4为例

#include <stdio.h>

#include<math.h>

#define N 4 /* 定义棋盘大小 */

static int sum; /* 当前已找到解的个数 */

static int x[N];

int place(int k)

{

    int j;

    for (j = 0; j < k; j ++)

        if (x[j] == x[k] || abs(j - k) == abs(x[j] - x[k]))

return 0;

         return 1;

}

/* 打印棋局 */

void chessboard()

{

    int i,j;

    int site[N];

     printf("第%d种解法:\n", ++ sum);

     for (i = 0; i < N; i ++) {

         for (j = 0; j < N; j ++)

             if (j == x[i]) {printf("Q ");site[i]=j+1;}

             else printf("* ");

     printf("\n");

     }

     printf("A%d(",sum);

     for(i = 0; i < N; i ++)

     {

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

     }

     printf(");");

     printf("\n");

}

/* 回溯搜索解空间 */

void backtrack()

{

    int k = 0;

    x[0] = -1;

    while (k >= 0) {

        x[k] += 1; /* 向右移一列 */

        /* 向右移至出最右列或可以放置皇后的列 */

        while ((x[k] < N) && !(place(k))) x[k] += 1;

        if (x[k] < N) /* 向右移未移出棋盘 */

            if (k == N - 1) chessboard(); /* 已移至最后一行 */

            else x[++ k] = -1; /* 向下移一行 */

        else k --; /* 回溯到上一行 */

    }

}

int main(void)

{

    backtrack();

    printf("%d皇后有%d个解:\n",N,sum);

    return 0;

}

实验结果截图:

5.     流程图


第二篇:河师大算法设计与分析N皇后问题实验报告


     计算机与信息技术学院实验报告

专业:计算机科学与技术  年级/班级:20##级      20##—20##学年第一学期

一、实验项目

N皇后问题

二、需求分析

八皇后问题是一个古老而著名的问题。该问题是十九世纪著名的数学家高斯1850年提出的。八皇后问题要求在一个8*8的棋盘上放上8个皇后,使得每一个皇后既不攻击到另外七个皇后,也不被另外七个皇后所攻击。按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子,问有多少种不同的摆法:并找出所有的摆法。因此,八皇后问题等于要求八个皇后中的任意两个不能被放置在同一行或同一列或同一斜线。

本次实验算法设计中,用到的主要知识有:递归法的运用,for 语句的灵活运用,数据结构中树知识的灵活运用、数组及动态数组技术的掌握。  系统要求:win98 以上操作系统;  语言平台:vc++6.0 或以上版本。

根据程序的设计要求,需要设计一个八皇后问题的演示程序,程序需要具备以下功能:能够快速查找并显示八皇后的布局方式有多少种正确方法。能够逐个查看每种布局的结果。能够很方便的改变皇后个数即棋盘规格。

三、概要设计:

本实验是用递归和回溯法来实现的,分别测试了每一种摆法,并将一个解图形化显示输出。在这程序中,思路主要是这样的:

1、解决冲突问题和数据结构的实现

对于数据结构的实现,则是着重于:

(1) 数组x[i]:表示第i个皇后放置的列;i的范围:0—n-1;

(2)  数据初始化

(3)  从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先用xx函数测试当前位置是未被占领;如果是,摆放第n-1个皇后后并宣布占领,接着进行递归;如果不是,测试下一个位置(n,m+1),但是如果当n<=8,m=8时,却发现此时已经无法摆放时,便要进行回溯。

(4)  当n=8时,便一一打印出结果。)

首先定义一个递归找全部的解的递归函数FindQueen(int i),设有一个参数i,表示1至i-1行都已有皇后合理放置的情况下,寻找第i行的合理放置。在i行上,有8种可能的放置,列j顺序选择第1列,第2列……直至第n列。当第i行j列的放置是合理的时候,就设置与i行j列相对应的列、斜线有皇后的标志并输出皇后,并在i=7(i从0开始计算)的情况下,看皇后位置是否合适,合适则弹出对话框,并把标记flag置为1;否则递归调用FindQueen(i+1),在第i+1行上寻找合理的放置,一列试探结束,再试探下一列前,清除已设置的与i行j列相对应的列,斜线有皇后的标志,让j增加1,在下一列寻找解。

再看如何表示一个解。由于每一列要放置一个皇后,所以,可以放置一个一维数组,称其为解数组,令其每个元素对应一行,其值等于该行上皇后所在的列号,即

                  X[i]==k

表示第i行上的第k列放置皇后。

要保存多个解时,可以设立多个这样的一维数组或一个二维数组。

下面考虑棋盘的表示。棋盘在这里是原始输入数据。但该问题与一般不同,只要知道棋盘的规模(即n×n),棋盘就完全确定了。此外,皇后的放置状态以用解数组x表示,因此,如果没有其他用途,棋盘的n×n的阵列表示是不需要显示给出的。

下边考虑冲突判别。如果已设置n×n阵列棋盘的表示,则可以对已放置了皇后的格子做标记,然后根据标记判别是否有冲突。若不设置n×n阵列,则可通过解数组x判别冲突。因为解数组已包含了全部的放置状态信息。

设目前要在i行j列放置皇后,考虑如何判断其是否u其他皇后冲突。冲突判别有下列几种:

(1)“是否为同行”,由于以行为单位放置皇后,所以不需要判断“是否为同行”

(2)“是否为同列”,这可以通过扫描解数组x得到,即查找x[1]~x[j-1]中,是否有值为i的元素。

(3)“是否为同斜线”,注意,n×n的阵列中有两种斜线——正斜线(/)和反斜线(\),各有2n-1条。同一条正斜线上,个元素的行号和列号之和相等;同一条反斜线上,个元素的行号和列号之差相等。因此,若有两个皇后的放置位置分别为(i,j)(g,h),则如果       i-j==g-h或i+j==g+h

则表示它们在同一斜线上,有冲突。这两个式子等价于

I-     g==j-h或i-g==h-j 其又等价于|i-g|==|j-h|

因此,判断(i,j)是否与当前放置的皇后冲突,可以通过扫描解数组x来完成,即检查x的每个元素x[k](其表示位置(x[k],k)上有皇后,k<j),若下式成立

         |i- x[k]|==|j-k|

则表明有冲突。

2、逻辑结构设计  

 类图

表汇总

3、模块设计

4、算法流程图

四、编程源代码:

# #include "stdio.h"

#include "stdlib.h"

#include "math.h"

Int  N ;         //定义棋盘的大小

int  sum = 0;          //当前已找到解的个数

int x[N];          //记录皇后的位置,x[i]表示皇后i放在棋盘的第i行的第x[i]列

/*每找到一个解,打印当前棋盘状态*/

void Show()

{

    sum++;

    printf("第%d种情况:",sum);

    printf("坐标为:\n");

    for(int k=0;k<N;k++)

        printf("(%d,%d)",k+1,x[k]);

    printf("\n");

    printf("----------------------\n");

    for(int i=0;i<N;i++)

    {

        for(int j=0;j<N;j++)

            if(j==x[i])printf("*|");       //prinft("@")

            else       printf(" |");        //printf("*")

            printf("\n---------------------------\n");

    }

}

/*确定某一位置皇后放置与否,放置则返回1,反之返回0*/

int Judge(int k)

{

//测试皇后k在第k行,第x[k]列时是否与前面已放置好的皇后相攻击。X[j]==x[k]时

//两皇后在同一列上;abs(k-j)==abs(x[j]-x[k])时,两皇后在 同一斜线上。两种情况两皇//后都可相互攻击,故返回0表示不符合条件。

    for(int j = 0; j < k; j++)

        if(abs(k-j) == abs(x[j] - x[k]) || x[j]==x[k])

            return 0;

    return 1;

}

/*主递归函数,搜索解空间中第i层子树*/

int Backtrack(int t)

{

    /*t==N时,算法搜索至叶节点,得到一个新的N皇后互不攻击的放置方案*/

    if(t==N)

        Show();

    else   

    {

        for(int i = 0; i < N; i++)

        {

            x[t] = i;

            if(Judge(t))

                Backtrack(t+1);

        }

    }

    return 0;

}

int main()

{    printf(“请输入棋盘大小(N):\n”);

     Scanf(“%d”,&N);

     Backtrack(0);

     printf("\n");

     system("pause");

     getchar();

     return 0;

}

运行结果:

当N=8时,输出的第92种情况:

 

五、心得体会

本程序通过关键函数Backtrack(int t)的调用,将N皇后的关键问题通过数据结构的思想予以了实现。虽然题目以及演算看起来都比较复杂,繁琐,但在实际中,只要当一只皇后放入棋盘后,在行与列、斜线上没有另外一只皇后与其冲突,再对皇后的定位进行相关的判断,即可完成。如果在程序中,我们运用的是非递归的思想,那么将大量使用if等语句,并通过不断地判断,去推答案,而且这种非递归的思想,大大增加了程序的时间复杂度。我们使用了数据结构中的算法后,程序的时间复杂度,以及相关的代码简化都能取得不错的改进。

在本次实验中,我们利用递归和回溯法求解n皇后问题。通过本次实验设计,明确了n皇后的概念。并通过本实验,熟悉回溯算法在程序设计中的应用方法。回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。回溯法士计算机科学里的常用方法,使用回溯、递归,可以将很复杂的问题再形式上予以简化,由于自己编程能力有限,本程序算法不够精炼,程序语句也不够简明。在编写程序时,对书上的算法语句还不能融汇贯通。今后一定多研读书中的代码,做到活学活用。

 


在初始状态下 棋盘上没有任何棋子。然后顺序在第1行,第2行,…,第n行上布置棋子。在每一行中有n个可选择的位置,但在任一时刻,棋盘的合法布局都必须满足3个限制条件:即任何两个棋子不得放在棋盘上的同一行、或者同一列、或者同一斜线上。

用回溯法。在第n行第j列安放一个棋子时,需要记录在行方向、列方向、正斜方向、反斜方向的安放状态,若当前布局合法,可向下一行递归求解,否则可移走这个棋子,回复安放此棋子前的状态,试探本行的j+1列。

更多相关推荐:
八皇后实验报告

实验项目1实验目的通过求解皇后问题熟悉深度优先搜索法DFS回溯法BacktrackingAlgorithms技术2实验内容由n2个方块排成n行n列的正方形称为n元棋盘如果两个皇后位于n元棋盘上的同一行同一列或同...

数据结构实验报告-八皇后问题

数据结构实验报告1.实验要求实验目的:利用栈结构实现八皇后问题八皇后问题如下:八皇后问题是19世纪著名的数学家高斯于1850年提出的。他的问题是,在8*8的棋盘上放置8个皇后,使其不能互相攻击,即任意两个皇后都…

八皇后实验报告

北京邮电大学信息与通信工程学院数据结构实验报告实验名称实验二八皇后问题学生姓名姜山班级20xx211106班内序号14学号20xx210167日期20xx年11月16日1实验要求实验目的1进一步掌握指针模板类异...

八皇后实验报告

实验名称编程实现八皇后问题验证性实验实验目标使用深度优先搜索算法以及回溯法的思想进行暴力解题实验任务用88的二维数组去模拟皇后所在的棋盘然后用1标记该位置可以放皇后用0来标记该位置不可以放皇后然后每次有一个合理...

八皇后数据结构实验报告 完整版

数据结构实验报告八皇后问题实验目的熟练掌握栈操作的基本算法实现实现功能利用回溯法和栈来实现八皇后问题在88的国际象棋棋盘上安放8个皇后要求没有一个皇后能够吃掉任何其他一个皇后即没有两个或两个以上的皇后占据棋盘上...

八皇后实验报告

目录一二三四五六引言2算法分析及流程2实验过程分析4结果与讨论5改进5结语7一算法分析及流程1八皇后问题是一个古老而著名的问题该问题是十九世纪著名的数学家高斯1850提出在88格的国际象棋上摆放八皇后使其不能互...

八皇后问题实验报告

软件工程上机报告实验名称八皇后问题图形界面求解姓名郭恂学号20xx011435班级11级数学班中国石油大学北京计算机科学与技术系一试验程序截图点击显示下一组解即可显示下一组解同样的如果点击上一组解即可显示上一组...

人工智能实验报告,包括八数码问题八皇后问题和tsp问题

八数码问题(一)问题描述在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。现在的问题是:…

八数码实验报告

利用人工智能技术解决八数码游戏问题1八数码游戏问题简介九宫排字问题又称八数码问题是人工智能当中有名的难题之一问题是在33方格盘上放有八个数码剩下第九个为空每一空格其上下左右的数码可移至空格问题给定初始位置和目标...

人工智能实验报告-八数码 (1)

人工智能实验一题目实验一启发式搜索算法1实验内容使用启发式搜索算法求解8数码问题编制程序实现求解8数码问题A算法采用估价函数wnfndnpn其中dn是搜索树中结点n的深度wn为结点n的数据库中错放的棋子个数pn...

八数码问题求解--实验报告

实验报告一实验问题八数码问题求解二实验软件VC60编程语言或其它编程语言三实验目的1熟悉人工智能系统中的问题求解过程2熟悉状态空间的盲目搜索和启发式搜索算法的应用3熟悉对八数码问题的建模求解及编程语言的应用四实...

人工智能A算法八数码报告

人工智能课程设计报告题目A算法解决八数码问题专业计算机软件与理论18数码问题11问题描述八数码问题是指这样一种游戏将分别标有数字1238的八块正方形数码牌任意地放在一块33的数码盘上放牌时要求不能重叠于是在33...

八皇后实验报告(30篇)