回溯算法实验报告

时间:2024.4.20

 

本科学生综合性实验报告

姓名 刘春云刘春云        学号 0103918__  _

    专业 软件工程  班级_软件103   _   _

实验项目名称_n皇后问题的回溯算法实验

指导教师及职称_   赵晓平__教授__

开课学期    20##   至_  20## 学年_  _学期

上课时间      20##     2        20 


学生实验报告(3)

一、问题描述

n后问题是指在一个n*n的棋盘上放置n个皇后,使得它们彼此不受攻击。而一个皇后可以攻击与它处在同一行或同一列或同一斜线上的任何棋子。故n后问题可以理解为:在一个n*n的棋盘内放置n个皇后,使任意两个皇后不处在同一行或同一列或同一斜线上。

在这个问题中,我用了一个n*n的数组来存储棋盘,由于n后问题的典型是8皇后问题,所以我做的是8皇后问题。得出的解以以下形式出现在文件中:

8皇后问题

第1个解为:

oxxxxxxx

xxxxoxxx

xxxxxxxo

xxxxxoxx

xxoxxxxx

xxxxxxox

xoxxxxxx

xxxoxxxx

二、解题思路

根据条件可以知道皇后肯定是每行都有且只有一个所以我们创建一个数组c[cur]让数组角标表示八皇后的行,用这个角标对应的数组值来确定这个皇后在这行的那一列。

我用递归来做这问题。要求皇后所在的位置必须和其他皇后的位置不在同一行、列和斜线上,所以这个限定条件可以用来判断一个皇后是否能放在当前位置。既然是用递归来解决问题那就要把这个问题分成一个个相同的小问题来实现。

这小问题是什么呢?不难发现我们要在n*n的方格里放好n个皇后那我们就要知道在n(列)*n-1(行)是怎么放的,再有我们事先写好的判断条件放好最后行就搞定了。以此类推我们要知道8*7的怎么方的我们就要知道8*6是怎么样的就好了。所以我们是以一行怎么放作为一个单元,每一行有n个位置可以放,每一个位置我们都要去判断一下所以我们就用循环来搞定。在这个循环里面我们让c[cur]=i也就是从这一行的第一个开始判断。先尝试放再去判断是否符合条件。如果符合条件我们就在调用这个函数本身向下一行搜索     

在进行判断下一行之前我们要判断一下cur是不是大于n也就是已经是最后一行了,如果是最后一行了我们就可以将其进行输出。打印n*n的矩阵皇后的位置用o表示出来没有的用x表示。

       三、算法描述

             分析:每个皇后在一行。做个n重循环,把每个皇后安排在每行的每个位置都试一遍。

1、棋盘是n*n数组,定义n+1个空棋盘。

2、第一个皇后从1行1列到1行n列循环。 

3、第二个皇后从2行1列到2行8列循环。

用 c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j]来判断是否与前面放置的皇后冲突若本点不符合,则此点能放棋子,继续搜索。否则退出循环

4、以此类推

在算法中#define n  8控制皇后个数 int *c; 指向n*n的数组指针 search函数是搜索下一行中哪列符合条件 

for(j=1;j<cur;j++)

         if(c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])//同列、同正对角线、同负对角线

{

                               ok=0;

                               break;

}/这个for循环检测是否与前cur-1行的皇后有冲突

四、算法实现

具体代码:

#include <iostream>

#include<fstream>

using namespace std;

#define n  8      //控制皇后个数

int *c;           //指向n*n的数组指针

void search(int cur)

{  

   void show();

   int i,j;

   if(cur==n+1)  

          show();//只要走到这,就一定可以有一组解并将它们输出

   else

          for(i=1;i<=n;i++)//按列搜索

          {

             bool ok=1;

             c[cur]=i;      //尝试将第cur行的皇后放入第i列

             for(j=1;j<cur;j++)//检测是否与前cur-1行的皇后有冲突

                    if(c[cur]==c[j]||cur-c[cur]==j-c[j]||cur+c[cur]==j+c[j])//同列、同正对角线、同负对角线

                       {

                          ok=0;

                          break;

                       }

             if(ok)

                   search(cur+1);//不冲突,继续搜索

          }

}

void show()

{

       ofstream outfile;

       outfile.open("output.txt",ios::app);//打开output文件

    static       int count=0;//静态变量计算解的个数

    outfile<<"第"<<++count<<"个解为:"<<endl;

    for(int i=1;i<=n;i++)//在文件中输出结果:o表示皇后在,x表示皇后不在

       {

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

              {

                if(c[i]==j)

            outfile<<"o";

                else

                       outfile<<"x";

              }

        outfile<<endl;

       }

}

void main()

{

       c=new int[n+1];

       ofstream outfile;

       outfile.open("output.txt",ios::app);//创建output文件

       outfile<<n<<"皇后问题"<<endl;        

       search(1);//由第一行开始搜索

outfile.close();

}

五、程序测试及分析

        

结果输出:

 

六、总结

回溯法是一种最一般的算法设计方法,特别适用于求解那些涉及到寻求一组解的问题或者求满足某些约束条件的最优解的问题。我解决n皇后问题用的算法正是基于回溯算法的思想提出的一种递归算法,并且找出了八皇后问题的92个真正不同的解,此算法具有结构清晰,容易理解且可读性强等优点,并且通过稍加变通也可以适用于其他类似问题,例如汉诺塔等。与非递归算法设计相比,它往往更容易一些,但是会耗费更多的时间和空间,执行效率不高。

七、导教师评语及成绩:

评语:

成绩:       指导教师签名:

                                               批阅日期:


第二篇:算法分析实验报告--回溯法


《算法设计与分析》实验报告

回溯法

一、试验名称:回溯法

(1)    写出源程序,并编译运行

(2)    详细记录程序调试及运行结果

二、实验目的

(1)   掌握回溯算法思想

(2)   掌握回溯递归原理

(3)   了解回溯法典型问题

三、实验内容

(1)   编写一个简单的程序,解决8皇后问题

(2)   批处理作业调度

(3)   数字全排列问题

四、算法思想分析

(1)    编写一个简单的程序,解决8皇后问题

(2)    批处理作业调度

[问题描述]给定n个作业的集合J=(J1, J2, … , Jn)。每一个作业Ji都有两项任务需要分别在2台机器上完成。每一个作业必须先由机器1处理,然后再由机器2处理。作业Ji需要机器i的处理时间为tji,i=1,2, … ,n; j=1,2。对于一个确定的作业调度,设Fji是作业i在机器i上完成处理的时间。则所有作业在机器2上完成处理的时间和成为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的n个作业,制定一个最佳的作业调度方案,使其完成时间和达到最小。

要求输入:

1、作业数

2、每个作业完成时间表:

要求输出:

1、最佳完成时间

2、最佳调度方案

提示

提示:算法复杂度为O(n!),建议在测试的时候n值不要太大,可以考虑不要超过12。

(3)数字全排列问题:

任意给出从1到N的N个连续的自然数,求出这N个自然数的各种全排列。如N=3时,共有以下6种排列方式:123,132,213,231,312,321。

注意:数字不能重复,N由键盘输入(N<=9)。

五、算法源代码及用户程序

(1)   编写一个简单的程序,解决8皇后问题

N皇后问题

代码1:

#include<stdio.h>

#define NUM 8                //定义数组大小int a[NUM + 1];

int main ()

{

 int a[100];

     int number;

     int i;

     int k;

     int flag;

     int notfinish = 1;

     int count = 0;     i = 1;                    //正在处理的元素下标,表示前i-1个元素已符合要求,正在处理第i个元素

     a[1] = 1;                 //为数组的第一个元素赋初值

     printf ("Result:\n");     while (notfinish)             //处理尚未结束

     {

   while (notfinish && i <= NUM)         //处理尚未结束且还没处理到第NUM个元素

   {

    for (flag = 1, k = 1; flag && k < i; k++)         //判断是否有多个皇后在同一行

             {

     if (a[k] == a[i])

     flag = 0;

    }

  

    for (k = 1; flag && k < i; k++)         //判断是否有多个皇后在同一对角线

             {

     if ((a[i] == a[k] - (k - i)) || (a[i] == a[k] + (k - i)))

     flag = 0;

    }    if (!flag)             //若存在矛盾不满足要求,需要重新设置第i个元素

             {

     if (a[i] == a[i - 1])         //若a[i]的值已经经过一圈追上a[i-1]的值

     {

      i--;             //退回一步,重新试探处理前的一个元素

      if (i > 1 && a[i] == NUM)

      {

       a[i] = 1;         //当a[i]的值为NUM时将a[i]的值置1

      }

      else if (i == 1 && a[i] == NUM)

      {

       notfinish = 0;         //当第一位的值达到NUM时结束

      }

      else

      {

       a[i]++;         //将a[i]的值取下一个值

      }

     }

     else if (a[i] == NUM)

     {

      a[i] = 1;

     }

     else

     {

      a[i]++;             //将a[i]的值取下一个值

     }

             }

    else if (++i <= NUM)         //第i位已经满足要求则处理第i+1位

    {

     if (a[i - 1] == NUM)         //若前一个元素的值为NUM则a[i]=1

     {

      a[i] = 1;

     }

     else

     {

      a[i] = a[i - 1] + 1;         //否则元素的值为前一个元素的下一个值

     }

    }

         }     

   if (notfinish)

   {

    ++count;

    printf ((count - 1) % 3 ? "[%2d]:" : "\n[%2d]:", count);

   

    for (k = 1; k <= NUM; k++)         //输出结果

             {

     printf (" %d", a[k]);

    }    if (a[NUM - 1] < NUM)         //修改倒数第二位的值

    {

     a[NUM - 1]++;

    }

    else

    {

     a[NUM - 1] = 1;

    }    i = NUM - 1;             //开始寻找下一个满足条件的解

         }}//while

     printf ("\n");

     return 0;

}

(2)   批处理作业调度

import java.util.*;

public class FlowShop

{

static int n; //作业数

static int f1; //机器1完成处理时间

static int f; //完成时间和

static int bestf; //当前最优值

static int[][] m; //各作业所需要的处理时间

static int[] x; //当前作业调度

static int[] bestx; //当前最优作业调度

static int[] f2; //机器2完成处理时间

public static void trackback(int i) {

if (i == n) {

for (int j = 0; j < n; j++) {

bestx[j] = x[j];

}

bestf = f;

} else {

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

f1 += m[x[j]][0];

if (i > 0) {

f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + m[x[j]][1];

} else {

f2[i] = f1 + m[x[j]][1];

}

f += f2[i];

if (f < bestf) {

swap(x, i, j);

trackback(i + 1);

swap(x, i, j);

}

f1 -= m[x[j]][0];

f -= f2[i];

}

}

}

private static void swap(int[] x, int i, int j) {

int temp = x[i];

x[i] = x[j];

x[j] = temp;

}

private static void test() {

n = 3;

int[][] testm = {{2, 1}, {3, 1}, {2, 3}};

m = testm;

int[] testx = {0, 1, 2};

x = testx;

bestx = new int[n];

f2 = new int[n];

f1 = 0;

f = 0;

bestf = Integer.MAX_VALUE;

trackback(0);

System.out.println(Arrays.toString(bestx));

System.out.println(bestf);

}

public static void main(String[] args)

{

test();

System.out.println("Hello World!");

}

}

(3)   数字全排列问题

#include "stdio.h"

#include "conio.h"

int num,cont=0;

main()

{   int i,n,a[30];

    printf("enter N :");

    scanf("%d",&num);

    for(i=1;i<=num;i++)

    a[i]=i;

    perm(a,1);

    printf("\n%d",cont);

    getch();

}

int perm(int b[], int i)

{int k,j,temp;

 
if(i==num)

    {for(k=1;k<=num;k++)

      printf("%d ",b[k]);

    printf("\t");

    cont++;

    }

 
else

   for(j=i;j<=num;j++)

   {temp=b[i];b[i]=b[j],b[j]=temp;

    perm(b,i+1);

    temp=b[i];b[i]=b[j],b[j]=temp;

    }

  return(0);

}

六、实验结果与思想

     这次的实验是回溯法,我也对回溯法有了一个基本印象,所谓回溯法,就是把所有的可行解都遍历一遍,遇到不可行的就回溯到上一步,然后通过添加约束条件和限界条件就可以得到最优解。

更多相关推荐:
算法实验报告

算法设计与分析实验报告班级姓名学号年月日目录实验一二分查找程序实现03页实验二棋盘覆盖问题分治法08页实验三01背包问题的动态规划算法设计11页实验四背包问题的贪心算法14页实验五最小重量机器设计问题回溯法17...

算法设计实验报告

算法设计课程报告课题名称算法设计与实现课题负责人名学号张樱紫0743111317同组成员名单角色无指导教师左劼评阅成绩评阅意见提交报告时间20xx年12月23日课程名称算法设计学生姓名张樱紫学生学号074311...

中南大学--算法实验报告

中南大学--算法实验报告,内容附图。

遗传算法实验报告

遗传算法实验报告姓名:**学号:**一、实验目的:熟悉和掌握遗传算法的运行机制和求解的基本方法。遗传算法是一种基于空间搜索的算法,它通过自然选择、遗传、变异等操作以及达尔文的适者生存的理论,模拟自然进化过程来寻…

算法设计实验报告

1hanoi塔packagesyyimportjavautilpublicclassHanoipublicstaticvoidmoveintnintaintbSystemoutprintlnquot把第quot...

算法实验报告

算法导论实验报告实验一快速排序1问题描述实现对数组的普通快速排序与随机快速排序2算法原理设要排序的数组是A0AN1首先选取一个数据普通快排选择的是最后一个元素随记快排是随机选择一个元素作为关键数据然后将所有比它...

算法分析与设计实验报告

排序问题求解实验日志实验题目排序问题求解实验目的1以排序分类问题为例掌握分治法的基本设计策略2熟练掌握一般插入排序算法的实现3熟练掌握快速排序算法的实现4理解常见的算法经验分析方法实验要求1生成实验数据要求编写...

算法实验报告

算法实验报告学号姓名实验一11问题描述打印以下nn方阵123456724252627282982340414243309223948494431102138474645321120373635343312191...

算法实验报告

南阳师范学院本科学生实验报告姓名丁利旺院系环旅学院专业地理信息科学班级13级4班实验课程名称地理信息系统算法基础指导教师及职称范红艳讲师开课时间20xx至20xx学年一学期南阳师范学院教务处编印实验名称目录实验...

算法设计实验报告一_

算法设计实验报告一实验内容题目1编程实现常见排序算法如插入排序归并排序快速排序随机化的快速排序等并统计不同输入规模下1组从小到大排序1组从大到小排序其余8组随机的平均物理执行时间2编程实现循环赛日程表设有n2k...

数据结构算法实验报告

数据结构算法实验报告总汇实验报告11根据112的排列函数的规格说明编写程序实现习题11和习题12所定义的函数习题11定义下列函数检查一个序列是否有序boolsortedintaintn解includeltstd...

算法实验报告一

算法设计与分析课程实验报告专业计算机科学与技术班级学号姓名日期20xx年10月18日23

算法实验报告(32篇)