回溯法实验(n皇后问题)(迭代法)

合集下载

n皇后问题实验报告

n皇后问题实验报告

n皇后问题实验报告n皇后问题实验报告引言:n皇后问题是一个经典的数学问题,它要求在一个n×n的棋盘上放置n个皇后,使得它们互相之间不能相互攻击,即任意两个皇后不能处于同一行、同一列或同一对角线上。

本实验旨在通过编程实现n皇后问题的求解,并探索不同算法在解决该问题上的性能差异。

实验步骤及结果:1. 回溯算法的实现与性能分析回溯算法是最常见的解决n皇后问题的方法之一。

它通过递归的方式遍历所有可能的解,并通过剪枝操作来提高效率。

我们首先实现了回溯算法,并对不同规模的问题进行了求解。

在测试中,我们将问题规模设置为4、8、12和16。

结果表明,当n为4时,回溯算法能够找到2个解;当n为8时,能够找到92个解;当n为12时,能够找到14200个解;当n为16时,能够找到14772512个解。

可以看出,随着问题规模的增加,回溯算法的求解时间呈指数级增长。

2. 启发式算法的实现与性能分析为了提高求解效率,我们尝试了一种基于启发式算法的解决方法。

在该方法中,我们使用了遗传算法来搜索解空间。

遗传算法是一种模拟生物进化过程的优化算法,通过进化操作(如选择、交叉和变异)来寻找问题的最优解。

我们将遗传算法应用于n皇后问题,并对不同规模的问题进行了求解。

在测试中,我们将问题规模设置为8、12和16。

结果表明,遗传算法能够在较短的时间内找到问题的一个解。

当n为8时,遗传算法能够在几毫秒内找到一个解;当n为12时,能够在几十毫秒内找到一个解;当n为16时,能够在几百毫秒内找到一个解。

相比之下,回溯算法在同样规模的问题上需要几秒钟甚至更长的时间。

3. 算法性能对比与分析通过对比回溯算法和启发式算法的性能,我们可以看到启发式算法在求解n皇后问题上具有明显的优势。

回溯算法的求解时间随问题规模呈指数级增长,而启发式算法的求解时间相对较短。

这是因为启发式算法通过优化搜索策略,能够更快地找到问题的解。

然而,启发式算法并非没有缺点。

回溯法实验(n皇后问题)(迭代法)

回溯法实验(n皇后问题)(迭代法)

算法分析与设计实验报告第三次附加实验附录:完整代码(回溯法)//回溯算法递归回溯n皇后问题#include<iostream>#include<time.h>#include<iomanip>#include"math.h"using namespace std;class Queen{friend int nQueen(int); //定义友元函数,可以访问私有数据private:bool Place(int k); //判断该位置是否可用的函数void Backtrack(int t); //定义回溯函数int n; //皇后个数int *x; //当前解long sum; //当前已找到的可行方案数};int main(){int m,n;for(int i=1;i<=1;i++){cout<<"请输入皇后的个数:"; //输入皇后个数cin>>n;cout<<"皇后问题的解为:"<<endl;clock_t start,end,over; //计算程序运行时间的算法start=clock();end=clock();over=end-start;start=clock();m=nQueen(n); //调用求解的函数cout<<n<<"皇后问题共有";cout<<m<<"个不同的解!"<<endl; //输出结果end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运行时间cout<<endl;}system("pause");return 0;}bool Queen::Place(int k)//传入行号{for(int j=1;j<k;j++){if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))//如果两个在同一斜线或者在同一列上,说明冲突,该位置不可用{return false;}}return true;}void Queen::Backtrack(int t){if(t>n){sum++;/*for(int i=1;i<=n;i++) //输出皇后排列的解{cout<<x[i]<<" ";}cout<<endl;*/}else{//回溯探索第i行的每一列是否有元素满足要求for(int i=1;i<=n;i++){x[t]=i;if(Place(t)){Backtrack(t+1);}}}}int nQueen(int n){Queen X; //定义Queen类的对象X//初始化XX.n=n;X.sum=0;int *p=new int[n+1]; //动态分配for(int i=0;i<=n;i++) //初始化数组{p[i]=0;}X.x=p;X.Backtrack(1);delete[] p;return X.sum;//输出解的个数}完整代码(回溯法)//回溯算法迭代回溯n皇后问题#include<iostream>#include<time.h>#include<iomanip>#include"math.h"using namespace std;class Queen{friend int nQueen(int); //定义友元函数private:bool Place(int k); //定义位置是否可用的判断函数void Backtrack(void); //定义回溯函数int n; // 皇后个数int *x; // 当前解long sum; // 当前已找到的可行方案数};int main(){int n,m;for(int i=1;i<=1;i++){cout<<"请输入皇后的个数:";cin>>n;cout<<n<<"皇后问题的解为:"<<endl;clock_t start,end,over; //计算程序运行时间的算法start=clock();end=clock();over=end-start;start=clock();m=nQueen(n); //调用求解皇后问题的函数cout<<n<<"皇后问题共有";cout<<m<<"个不同的解!"<<endl;end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运行时间cout<<endl;}system("pause");return 0;}bool Queen::Place(int k){for (int j=1;j<k;j++){if ((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) //如果两个皇后在同一斜线或者在同一列上,说明冲突,该位置不可用{return false;}}return true;}void Queen::Backtrack() //迭代法实现回溯函数{x[1] = 0;int k = 1;while(k>0){x[k] += 1; //先将皇后放在第一列的位置上while((x[k]<=n)&&!(Place(k))) //寻找能够放置皇后的位置{x[k] += 1;}if(x[k]<=n) //找到位置{if(k == n) //如果寻找结束输出结果{/*for (int i=1;i<=n;i++){cout<<x[i]<<" ";}cout<<endl; */sum++;}else//没有结束则找下一行{k++;x[k]=0;}}else//没有找到合适的位置则回溯{ k--; }}}int nQueen(int n){Queen X; //定义Queen类的对象X//初始化XX.n=n;X.sum=0;int *p=new int[n+1];for(int i=0;i<=n;i++){p[i]=0;}X.x=p;X.Backtrack();delete []p;return X.sum; //返回不同解的个数}。

oeisn皇后问题数学解法

oeisn皇后问题数学解法

oeisn皇后问题数学解法OEISN皇后问题OEISN皇后问题即为在一个n*n的棋盘上放置n个皇后,使得每行、每列和每条对角线上只有一个皇后,求解最优解。

概述OEISN皇后问题,是经典的NP完全问题,这意味着,在多项式时间内无法求出此问题的最优解。

目前已知求解该问题的最好算法是基于backtrack的算法,通过枚举所有的情况,寻找满足条件的最优解。

解法步骤下面将介绍一种基于回溯法的OEISN皇后问题的解法。

1. 生成初始状态首先,生成一个初始状态,即在每一行中随机选择一个位置放置一个皇后。

2. 迭代搜索接下来,进行迭代搜索。

从第一行开始,依次在每一行中选择一个位置来放置皇后。

如果放置的皇后不满足条件,则尝试在该行中选择其他位置放置。

如果在该行中的所有位置都不能放置皇后,那么回溯到上一行重新选择位置。

3. 结束条件在每一行都完成放置皇后的任务后,判断当前解是否满足条件。

如果满足条件,统计解的数量,并返回上一行。

否则,回溯到上一行,重新选择位置。

4. 输出解在整个搜索过程结束后,输出所有找到的最优解,并统计总解的数量。

优缺点与其他的NP完全问题相比,OEISN皇后问题通过backtrack算法进行求解,相对来说解法较为简单。

但是,也存在其缺点。

由于该问题是基于穷举法的搜索,需要枚举所有情况,所以对于大规模的问题,该算法存在时间复杂度高的问题。

实例解释下面,我们以n=4的情况为例,来解释该算法的求解过程。

初始状态:在这个初始状态下,我们依次枚举每一行下的位置。

首先,选择在第一行的第一个位置下放置皇后。

由于第二行的任何位置都不能与第一行的皇后不共线,所以,在第二行的第三个位置放置皇后。

在第三行中,第一和第四个位置与已经放置的皇后不共线,所以这里我们选择第一列放置皇后。

在最后一行中,只有第一列能满足要求。

统计到此时,我们已经找到了一个最优解。

不难发现,该算法从第一行到第四行依次枚举每一个位置,由于对于每一行我们都进行了全面的搜索,所以我们可以保证找到的最优解一定是全局最优解。

回溯法求解N皇后问题

回溯法求解N皇后问题

算法的实现
• 假设回溯法要找出所有的答案结点 。 • 设(x1,x2,…,xi-1)是状态空间树中由根到一个结 点的路径,而T(x1,…xi-1)是下述所有结点xi的 集合,它使得对于每一个xi,(x1,x2,…,xi)是由 根到一个结点xi的路径;假定还存在着一些限 界函数Bi,如果路径(x1,x2,…,xi)不可能延伸到 一个答案结点,则Bi(x1,x2,…,xi)取假值,否则 取真值。 • 于是解向量X(1:n)中的第i个分量,就是那些 选自集合T (x1,x2,…,xi-1)且使Bi为真的xi
HHIT
算法8.5:n-皇后问题的解
Algorithm
Procedure NQUEENS(n) //此过程使用回溯法求出一个n*n棋盘上放置n个皇后,使其不能互相攻 击的所有可能位置// integer k,n,X(1:n) X(1)0 ; k1 // k是当前行;X(k)是当前列 // while k>0 do // 对所有的行,执行以下语句 // X(k)X(k)+1 //移到下一列// while X(k)<=n and Not PLACE(k) do //此处能放这个皇后吗// X(k)X(k)+1 //不能放则转到下一列// repeat if X(k)<=n then //找到一个位置// if k=n then print (X) //是一个完整的解则打印这个数组// else kk+1;X(k)0 //否则转到下一行// end if else kk-1 //回溯// end if repeat End NQUEENS
HHIT
Algorithm
显然,棋盘的每一行上可以而且必须摆放一个皇后, 所以,n皇后问题的可能解用一个n元向量X=(x1, x2, …, xn) 表示,其中,1≤i≤n并且1≤xi≤n,即第i个皇后放在第i行第 xi列上。 由于两个皇后不能位于同一列上,所以,解向量X必 须满足约束条件: xi≠xj (式8.1)

n皇后 实验报告

n皇后 实验报告

n皇后实验报告n皇后实验报告引言:n皇后问题是一个经典的数学问题,其目标是在一个n×n的棋盘上放置n个皇后,使得它们互不攻击。

本实验旨在通过编程实现n皇后问题的解法,并对不同的算法进行性能分析。

实验方法:本实验采用Python语言编写程序,实现了两种常见的解法:回溯法和遗传算法。

回溯法是一种穷举搜索的方法,通过不断尝试每一种可能的放置方式,直到找到满足条件的解;而遗传算法则是通过模拟生物进化的过程,利用选择、交叉和变异等操作逐步优化解的质量。

实验结果:在实验中,我们分别测试了回溯法和遗传算法在不同规模的n皇后问题上的性能表现。

以下是实验结果的总结:1. 回溯法:- 对于规模较小的问题(n<10),回溯法可以在短时间内找到所有解,并输出结果。

- 随着问题规模的增大,回溯法的搜索时间呈指数级增长。

当n=15时,搜索时间已经超过10秒。

- 回溯法在解决大规模问题时,遇到了组合爆炸的问题,无法在合理的时间内得出结果。

2. 遗传算法:- 遗传算法对于规模较小的问题表现不如回溯法,因为其需要较长的时间来找到一个较优解。

- 随着问题规模的增大,遗传算法的性能逐渐超过回溯法。

当n=20时,遗传算法能够在合理的时间内找到一个较优解。

- 遗传算法在解决大规模问题时,相比回溯法有明显的优势,因为其搜索时间增长较慢。

实验讨论:通过对实验结果的分析,我们可以得出以下结论:- 回溯法适用于规模较小的n皇后问题,但在大规模问题上的性能不佳。

- 遗传算法在大规模问题上表现较好,但对于规模较小的问题需要更长的时间来找到较优解。

- 遗传算法的性能受到参数设置的影响,不同的选择、交叉和变异策略可能导致不同的结果。

结论:综上所述,回溯法和遗传算法都是解决n皇后问题的有效方法,但在不同规模的问题上有不同的性能表现。

在实际应用中,我们可以根据问题规模选择合适的算法来求解。

对于规模较小的问题,回溯法可以提供精确的解;而对于大规模问题,遗传算法能够在合理的时间内找到较优解。

n皇后问题算法实验报告

n皇后问题算法实验报告

算法分析与设计实验报告实验内容:N皇后问题实验时间:2014-11-19姓名:杨晨班级:软件12k2学号:121909020221一、实验内容及要求在n×n格的棋盘上放置彼此不受攻击的n个皇后,按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

二、实验目的1.巩固和加深对回溯法的理解2.了解递归和迭代法在回溯法中的应用三、算法分析1.理解皇后不被攻击的条件:n后问题等价于在n*n格的棋盘上放置n个皇后,任何两个皇后不能放在同一行或同一列或同一斜线上。

2.算法模块简要分析用数组存储皇后的位置,将i设置为0.Int place(*x,n) :数组x[] 用来表示列数,n为皇后个数,用来判断皇后是否被攻击,判断的条件是(x[i]-x[n]==i-n||x[i]-x[n]==n-i||x[i]==x[n])即用来判断“同一行或同一列或同一斜线上”。

Int print(*x,n):打印皇后解的空间。

Int iniprint(*x,n):初始化打印函数,相当于对棋盘初始化。

将可以放皇后的位置记为“1”,不放皇后的位置记为“0”。

Int Nqueen(int n):n皇后问题求解,如果满足一组可行解,sum++。

Int i=0,如果x[i]>=n的时候即进行下一行,i++;当i=n时,sum++;输出该组可行解的个数和位置的矩阵。

并且i--,回溯到上一层继续搜索可行解。

四、运行结果及分析1、三皇后没有可行解2、2.4个皇后有2个可行解3.5皇后有10个可行解五、源代码#include<stdio.h>static int n, sum=0;//可行解个数static int locate[20];int place(int k){//判断是否在一条线上并返回0,1for(int i=1;i<k;i++){if(locate[i] == locate[k] || (i+locate[i])==(locate[k]+k)||(locate[i]-i)==(locate[k]-k))return 0;}return 1;}void Back(int m){if(m>n){sum++;for(int i=1;i<=n;i++){for(int a=1;a<=n;a++){if(a<locate[i]||a>locate[i])printf(" * ");elseprintf(" \2 "); //如果已经安排完毕则输出棋盘和记录}printf("\n");}printf("第%d种解法如上图所示: ",sum);for(int i=1;i<=n;i++)printf("%d ",locate[i]);printf("\n\n\n");}else{//如果没有安排完则递归继续下一个安排,无解则返回上一个for(int i=1;i<=n;i++){locate[m]=i;if(place(m))Back(m+1);}}}int main(){printf("请输入皇后数量:");scanf("%d",&n);printf("\n(\2表示皇后,*表示棋盘)\n\n\n");Back(1);printf("%d个皇后共有以上%d种解法\n\n\n",n,sum);}六、实验心得回溯法有“通用解题法”之称,用它可以搜索问题的所有解。

N皇后问题实验报告C++版

N皇后问题实验报告C++版

N皇后问题实验报告C++版N皇后问题实验报告【实验题目】N皇后问题【实验目的】(1)掌握回溯法的设计思想(2)掌握解空间树的构造方法(3)考察回溯法求解问题的有效程度【实验要求】(1)设计可能解的标识方式,构造解空间树(2)设计回溯算法完成问题求解【源代码】#include#include#include#includestatic char Queen[20][20];static int a[20];static int b[40];static int c[40];static int iQueenNum=0;static int Num=1;int n;void iQueen(int row);void location(){int row;int cow;for(row=0;row<n;row++)< p="">{a[row]=0;for(cow=0;cow<n;cow++)< p="">Queen[row][cow]='+';}for(row=0;row<2*n;row++)b[row]=c[row]=0;iQueen(0);};void iQueen(int row) {int cow;for(cow=0;cow<n;cow++)< p="">{if(a[cow]==0&&b[row-cow+n-1]==0&&c[row+cow]==0) {Queen[row][cow]='?';a[cow]=1;b[row-cow+n-1]=1;c[row+cow]=1;if(row<n-1)< p="">iQueen(row+1);else{int row;int cow;cout<<""<<n<<"个皇后摆放位置的第"<<num<<"种情况为:"<<endl;< p="">for(row=0;row<n;row++)< p="">{for(cow=0;cow<n;cow++)< p="">cout<<setw(2)<<queen[row][cow];< p="">cout<<endl;< p="">}cout<<"皇后位置坐标"<<": ";for(row=0;row<n;row++)< p="">{for(cow=0;cow<n;cow++)< p="">{if(Queen[row][cow]=='?')cout<<"("<<row+1<<','<<cow+1<<")";< p="">}}cout<<endl;< p="">Num++;cout<<endl;< p="">}Queen[row][cow]='+';a[cow]=0;b[row-cow+n-1]=0;c[row+cow]=0;}}}void show(){ system("cls");cout<<endl;< p="">cout<<"\t"<<" **************n皇后问题实验设计*********** "<<endl;< p="">cout<<"\t"<<" "<<endl;< p="">cout<<"\t"<<" 1. 回溯算法 0.退出"<<endl;< p="">cout<<"\t"<<" "<<endl;< p="">cout<<"\t"<<"请选择 1或者0"<<endl;< p=""> }int main(){ system("color 5E");for(;;){ A:show();cout<<endl;< p="">int number;cin>>number;switch(number){case 0: exit(0);case 1: system("cls");cout<<"输入皇后个数(个数大于4):";cin>>n;location();system("pause");goto A;default:cout<<"选择错误,请重新作出选择!"<<=""> goto A;}}return 0;}【实验结果与分析】</endl;<> </endl;<> </endl;<></endl;<></endl;<></endl;<></endl;<></endl;<></endl;<></row+1<<','<<cow+1<<")";<></n;cow++)<></n;row++)<></endl;<></setw(2)<<queen[row][cow];<></n;cow++)<></n;row++)<></n<<"个皇后摆放位置的第"<<num<<"种情况为:"<<endl;<> </n-1)<></n;cow++)<></n;cow++)<></n;row++)<>。

用回溯算法解n皇后问题实验步骤

用回溯算法解n皇后问题实验步骤

湖州师范学院实验报告课程名称:算法实验四:回溯算法一、实验目的1、理解回溯算法的概念,掌握回溯算法的基本要素。

2、掌握设计回溯算法的一般步骤,针对具体问题,能应用回溯算法求解。

二、实验内容1、问题描述1 )n后问题在n×n格的棋盘上放置彼此不受攻击的n个皇后。

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

2)0-1 背包问题需对容量为 c 的背包进行装载。

从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。

对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。

每种物品要么放进背包,要么丢弃。

2、数据输入:文件输入或键盘输入。

3、要求:1)完成上述两个问题,时间为2 次课。

2)独立完成实验及实验报告。

三、实验步骤1、理解方法思想和问题要求。

2、采用编程语言实现题目要求。

3、上机输入和调试自己所写的程序。

4、附程序主要代码:1.n后问题:#include<iostream>using namespace std;class Queen {friend int nQueen(int);private:bool Place(int k);void Backtrack(int t);int n,*x;long sum;};bool Queen::Place(int k) {for (int j = 1; j < k; j++)if ((abs(k - j) == abs(x[j] - x[k])) || (x[j] == x[k]))return false;return true;}void Queen::Backtrack(int t) {if (t > n) {for (int i = 1; i <= n; i++)cout << x[i] << " ";cout << endl;sum++;}else {for (int i = 1; i <= n; i++) {x[t] = i;if (Place(t)) Backtrack(t + 1);}}}int nQueen(int n) {Queen X;//初始化XX.n = n;X.sum = 0;int* p = new int[n + 1];for (int i = 0; i <= n; i++)p[i] = 0;X.x = p;X.Backtrack(1);delete [] p;return X.sum;}void main() {int n, set;cout << "请输入皇后个数:"; cin >> n;cout << "可行方案所有解:" << endl;set = nQueen(n);cout << "可行方案数:" << set << endl;}2.0-1背包:#include <stdio.h>#include <conio.h>int n;//物品数量double c;//背包容量double v[100];//各个物品的价值double w[100];//各个物品的重量double cw = 0.0;//当前背包重量double cp = 0.0;//当前背包中物品价值double bestp = 0.0;//当前最优价值double perp[100];//单位物品价值排序后int order[100];//物品编号int put[100];//设置是否装入//按单位价值排序void knapsack(){int i,j;int temporder = 0;double temp = 0.0;for(i=1;i<=n;i++)perp[i]=v[i]/w[i];for(i=1;i<=n-1;i++){for(j=i+1;j<=n;j++)if(perp[i]<perp[j]) perp[],order[],sortv[],sortw[] {temp = perp[i];perp[i]=perp[i];perp[j]=temp;temporder=order[i]; order[i]=order[j]; order[j]=temporder; temp = v[i];v[i]=v[j];v[j]=temp;temp=w[i];w[i]=w[j];w[j]=temp;}}}//回溯函数void backtrack(int i){double bound(int i);if(i>n){bestp = cp;return;}if(cw+w[i]<=c){cw+=w[i];cp+=v[i];put[i]=1;backtrack(i+1);cw-=w[i];cp-=v[i];}if(bound(i+1)>bestp)//符合条件搜索右子数 backtrack(i+1);}//计算上界函数double bound(int i){double leftw= c-cw;double b = cp;while(i<=n&&w[i]<=leftw){leftw-=w[i];b+=v[i];i++;}if(i<=n)b+=v[i]/w[i]*leftw;return b;}int main(){int i;printf("请输入物品的数量和容量:");scanf("%d %lf",&n,&c);printf("请输入物品的重量和价值:");for(i=1;i<=n;i++){printf("第%d个物品的重量:",i);scanf("%lf",&w[i]);printf("价值是:");scanf("%lf",&v[i]);order[i]=i;}knapsack();backtrack(1);printf("最有价值为:%lf\n",bestp);printf("需要装入的物品编号是:");for(i=1;i<=n;i++){if(put[i]==1)printf("%d ",order[i]);}return 0;}5、实验结果:四、实验分析1、:n后问题分析只要不要在同一直线和斜线上就行。

回溯算法解决N皇后问题实验及其代码

回溯算法解决N皇后问题实验及其代码

实验报告4回溯算法实验4回溯算法解决N皇后问题一、实验目的1)掌握回溯算法的实现原理,生成树的建立以及限界函数的实现;2)利用回溯算法解决N皇后问题;二、实验内容回溯算法解决N皇后问题。

三、算法设计1)编写限界函数bool PLACE(int k,int x[]),用以确定在k列上能否放置皇后;2)编写void NQUEENS(int n)函数用以摆放N个皇后;3)编写主函数,控制输入的皇后数目;4)改进和检验程序。

四、程序代码//回溯算法解决N皇后问题的c++程序#include<math.h>#include<iostream>using namespace std;int count=0; //皇后摆放的可能性bool PLACE(int k,int x[]);//限界函数void NQUEENS(int n);//摆放皇后int main(){}int queen;cout<<"先生(女士)请您输入皇后的总数,谢谢!:"<<endl;cin>>queen;NQUEENS(queen);cout<<"所有可能均摆放完毕,谢谢操作"<<endl;return 0;void NQUEENS(int n){/*此过程使用回溯算法求出在一个n*n棋盘上放置n个皇后,使其即不同行,也不同列,也不在同一斜角线上*/int k, *x=new int[n];//存放皇后所在的行与列x[0]=0;k=0;while (k>=0&&k<n){ //对所有的行执行以下语句x[k]=x[k]+1; //移到下一列while(x[k]<=n&&(!PLACE(k,x))){ //此处能放置一个皇后吗?}if( x[k]<=n ) { //找到一个位置if( k==n-1 ){ //是一个完整的解吗cout<<"第"<<++count<<"排法是:"<<endl;for(int i=0;i<n;i++)//打印皇后的排列{}cout<<"\n";for (int j=0;j<n;j++){}cout<<"\n";if (x[i] == j+1){}else{}cout<<". ";cout<<"*";x[k]=x[k]+1; //移到下一列}}}}else { k=k+1; x[k]=0;} //移向下一行else k=k-1; //回溯bool PLACE(int k,int x[]){/*如果一个皇后能放在第k行和x(k)列,返回ture;否则返回false。

n皇后问题实验报告

n皇后问题实验报告

N后问题算法一、实验目的及要求所要涉及或掌握的知识:1. 了解皇后相互攻击的条件:如果任意两个皇后在同一行,同一列或同一对角线,则她们相互攻击。

2. 运用迭代的方法实现6皇后问题,求解得到皇后不相互攻击的一个解3. 在运用迭代的方法实现编程时,要注意回溯点二、问题描述及实验内容对6皇后问题求解,用数组c[1…6]来存皇后的位置。

c[i]=j表示第i个皇后放在第j列。

最后程序运行的结果是c[1…6]={1,5,8,6,3,7 }三、问题分析和算法描述6-QUEENS的算法表示:输入:空。

输出:对应于6皇后问题的解的向量c[1…6]={1,5,8,6,3,7}1. for k=1 to 62. c[k]=0 //没有放皇后3. end for4. flag=false5. k=16. while k>=17.while c[k]<=58.c[k]=c[k]+19.if c为合法着色 then set flag=ture 且从两个while循环退出10.else if c是部分解 then k=k+111.end while12. c[k]=0 //回溯并c[k]=013. k=k-114. end while15. if flag then output c16. else output “no solution”四、具体实现# include <math.h>#include <time.h>#include <stdlib.h>#include <stdio.h>#include "iostream"using namespace std;int total = 0; //方案计数void backtrace(int queen[],int N){int i, j, k;cout<<"★为皇后放置位置\n";for (i=1;;){ //首先安放第1行if(queen[i]<N){ //皇后还可调整k=0; //检查与第k个皇后是否互相攻击while(k<i&&abs(queen[k]-queen[i])&&(abs(queen[k]-queen[i])-abs(k-i))) k++;if (k<=i-1){ //与第k个皇后互相攻击queen[i]++; //第i个皇后右移一列,重测continue;}i++; //无冲突,安置下一行皇后if(i<N) continue;cout<<"第"<<total+1<<"种为:\n";for(int i=0;i<N;i++){for(int j=0;j<queen[i];j++)cout<<"□";cout<<"★";for(int k=queen[i]+1;k<N;k++)cout<<"□";cout<<endl;}total++; //方案数加1if(total%5==0) cout<<endl;queen[N-1]++; // 将第8个皇后右移一列,前8个不动i=N-1; //此处是制造机会,如不成功则回溯,关键一步}else //当前行皇后无法安置,回溯{queen[i]=0; //当前行皇后回归1列i--; //回溯到前一行皇后if(i<0){ //回溯到数组1行之前,结束cout<<"\n针对 "<<N<<" 皇后问题,"<<"一共找到 "<<total<<" 种放置方法。

回溯问题:m点着色、n皇后、tsp递归迭代算法

回溯问题:m点着色、n皇后、tsp递归迭代算法

m着色回溯法递归//输入n为顶点个数,颜色数m,图的邻接矩阵c[][]//输出n个顶点的着色x[]//递归方法求解#include <iostream>using namespace std;bool c[6][6];int x[6];int m=3;int n=5;bool ok(int k) //判断对顶点k着色以后是否合法着色{int i;for(i = 1; i < k; i++)if((c[k][i]==1 && x[k] ==x[i]))return false;return true;}void output(int x[]){cout<<"The feasibleresult is:"<<endl;for(int i=1;i<=n;i++)c out<<x[i]<<' ';cout<<endl;return;}void backtrack (int t){if (t>n) output(x);elsefor (int i=1;i<=m;i++) {x[t]=i;if (ok(t)) backtrack(t+1);x[t]=0;}}int main(){int i, j;for(i = 1; i < 5; i++)for(j = 1; j < 5;j++)c[i][j] = false;c[1][2] = true;c[1][3] = true;c[2][3] = true;c[2][4] = true;c[2][5] = true;c[3][5] = true;c[4][5] = true;c[2][1] = true;c[3][1] = true;c[3][2] = true;c[4][2] = true;c[5][2] = true;c[5][3] = true;c[5][4] = true;backtrack(1);cout << endl;return 0;}m着色回溯法迭代//输入n为顶点个数,颜色数m,图的邻接矩阵c[][]//输出n个顶点的着色x[]//第一个结点也可以有m种着色方案#include <iostream>using namespace std;bool c[6][6];int x[6];int m=3;int n=5;bool ok(int k) //判断对顶点k着色以后是否合法着色{int i;for(i = 1; i < k; i++)if((c[k][i]==1 && x[k] ==x[i]))return false;return true;}void m_coloring(int n, int m){int i, k;for(i = 1; i <= n; i++)x[i] = 0;k =1;while(k >=1){x[k]++;while(x[k] <= m)if( ok(k)==1) break;else x[k]++;if(x[k] <= m &&k==n){for(i=1;i<=n;i++)cout<<x[i]<<" ";cout<<endl;k--;//return;如果只需要一个解可以将上两句去掉,加入返回语句}else if(x[k]<=m&&k<n)k++;else{x[k]=0;k--;}}}int main(){int i, j;for(i = 1; i < 5; i++)for(j = 1; j < 5;j++)c[i][j] = false;c[1][2] = true;c[1][3] = true;c[2][3] = true;c[2][4] = true;c[2][5] = true;c[3][5] = true;c[4][5] = true;c[2][1] = true;c[3][1] = true;c[3][2] = true;c[4][2] = true;c[5][2] = true;c[5][3] = true;c[5][4] = true;m_coloring(5, 3);cout << endl;return 0;}//递归方法求解n皇后问题#include <iostream>using namespace std;#define Q_num 4int x[Q_num]; //存放每行棋子位置int number=0; //存放棋盘解的个数void output(int x[]){cout<<"棋盘放置位置如图:"<<endl;for(inti=1;i<=Q_num;i++){for(intj=1;j<=Q_num;j++){if(j==x[i])printf("%3d",x[i]);elseprintf("%3d",0);}cout<<endl;}cout<<endl;}bool Place(int k) //考察皇后k放置在x[k]列是否发生冲突{for (int i=1; i<k; i++)i f (x[k]==x[i] ||abs(k-i)==abs(x[k]-x[i]))return false;r eturn true;}int Queue_backtrack(int t){if (t>Q_num) {number++;output(x);}elsefor (inti=1;i<=Q_num;i++) {x[t]=i;if (x[t] <= Q_num&& Place(t))Queue_backtrack(t+1);x[t]=0;}returnnumber;}int main(){int i;for(i = 1; i <=Q_num;i++)x[i] = 0;cout<<"共有解:"<<Queue_backtrack(1)<<"个"<<endl;cout << endl;return 0;}//回溯法迭代求解n皇后问题#include <iostream>using namespace std;#define Q_num 8int x[Q_num]; //存放每行棋子位置int number=0; //存放棋盘解的个数void output(int x[]){for(inti=1;i<=Q_num;i++){for(intj=1;j<=Q_num;j++){if(j==x[i])printf("%3d",x[i]);elseprintf("%3d",0);}cout<<endl;}cout<<endl;return;}bool Place(int k) //考察皇后k放置在x[k]列是否发生冲突{for (int i=1; i<k; i++)i f (x[k]==x[i] ||abs(k-i)==abs(x[k]-x[i]))return false;r eturn true;}int Queue(int n){int i, k;for(i =0; i <= n; i++)x[i] = 0;k =1;while(k >=1){x[k]++;while(x[k] <= n&& !Place(k))x[k]++;i f(x[k] <= n &&k==n){number++;cout<<"棋盘放置具体位置如图:"<<endl<<endl;output(x);//return;如果只需要一个解}e lse if (x[k]<=n&& k<n)k++;else{x[k]=0;k--;}}return number; }int main(){cout<<"共有"<<Queue(Q_num)<<"个解"<<endl;return 0;}//递归方法实现哈密顿回路问题//指定一个城市为出发城市#include <string.h>#include <iostream>using namespace std;bool c[6][6];int x[6];int n=5;void output(int x[]){for(int i=1;i<=n;i++)c out<<x[i]<<' ';cout<<endl;return;}void hamilton(int k ){if(k>n && c[x[k-1]][1]==1)output(x);elsef or(int i=k;i<=n;i++){swap(x[k],x[i]);if ( c[x[k-1]][x[k]]==1)hamilton(k+1);swap(x[i],x[k]);}}int main(){int n = 5;memset(c, 0, sizeof(c));c[1][2] = true;c[2][1] = true;c[1][4] = true;c[4][1] = true;c[2][4] = true;c[4][2] = true;c[2][3] = true;c[3][2] = true;c[3][5] = true;c[5][3] = true;c[4][5] = true;c[5][4] = true;c[2][5] = true;c[5][2] = true;c[3][4] = true;c[4][3] = true;for(int i = 0; i <= n;i++){x[i] = i;}hamilton(2);//默认以第一个城市开始,搜索解空间树(子集树形式)直接从第二层开始//如果出发城市也可任选,则需要将c[0][i]=1,i=1~n,此时调用hamilton(1)即可cout << endl;return 0;}//哈密顿回路问题回溯法,解空间树按子集树构造,//采用迭代法实现//起始结点(出发城市)默认以第一个开始#include <string.h>#include <iostream>using namespace std;void hamilton(int n, int x[], boolc[6][6]){int i, k;bool*visited = new bool[n+1];for(i = 1; i <= n; i++){x[i] = 0;visited[i] = false;}visited[1]=1;x[1]=1;//默认以第一个城市开始k =2; //搜索解空间树(子集树形式)直接从第二层开始while(k >1){x[k]++;while(x[k] <= n)if(visited[x[k]]==0 &&c[x[k - 1]][x[k]]==1)break;elsex[k]++;if(x[k] <= n && k==n&& c[x[k]][1]==1){f or(k=1;k<=n;k++)cout<<x[k]<<' ';cout<<endl;k--;// break;输出一个解结束时用他替代上两句}else if(x[k]<=n &&k<n)//k!=n-1){v isited[x[k]]=1;k++;}else{x[k]=0;k--;visited[x[k]]=0;}}delete []visited; }int main(){int n = 5;bool c[6][6];memset(c, 0, sizeof(c));c[1][2] = true;c[2][1] = true;c[1][4] = true;c[4][1] = true;c[2][4] = true;c[4][2] = true;c[2][3] = true;c[3][2] = true;c[3][5] = true;c[5][3] = true;c[4][5] = true;c[5][4] = true;c[2][5] = true;c[5][2] = true;c[3][4] = true;c[4][3] = true;int x[6];hamilton(5, x, c);cout << endl;return 0;}。

实验报告:回溯法求解N皇后问题(Java实现)

实验报告:回溯法求解N皇后问题(Java实现)

实验报告一、实验名称:回溯法求解‎N皇后问题‎(Java实‎现)二、学习知识:回溯法:也称为试探‎法,它并不考虑‎问题规模的‎大小,而是从问题‎的最明显的‎最小规模开‎始逐步求解‎出可能的答‎案,并以此慢慢‎地扩大问题‎规模,迭代地逼近‎最终问题的‎解。

这种迭代类‎似于穷举并‎且是试探性‎的,因为当目前‎的可能答案‎被测试出不‎可能可以获‎得最终解时‎,则撤销当前‎的这一步求‎解过程,回溯到上一‎步寻找其他‎求解路径。

为了能够撤‎销当前的求‎解过程,必须保存上‎一步以来的‎求解路径,这一点相当‎重要。

三、问题描述N皇后问题‎:在一个 N * N 的国际象棋‎棋盘中,怎样放置 N 个皇后才能‎使N 个皇后之间‎不会互相有‎威胁而共同‎存在于棋局‎中,即在 N * N 个格子的棋‎盘中没有任‎何两个皇后‎是在同一行‎、同一列、同一斜线上‎。

深度优先遍‎历的典型案‎例。

四、求解思路1、求解思路:最容易想到‎的方法就是‎有序地从第‎1列的第 1 行开始,尝试放上一‎个皇后,然后再尝试‎第2 列的第几行‎能够放上一‎个皇后,如果第 2 列也放置成‎功,那么就继续‎放置第 3 列,如果此时第‎3列没有一行‎可以放置一‎个皇后,说明目前为‎止的尝试是‎无效的(即不可能得‎到最终解),那么此时就‎应该回溯到‎上一步(即第 2 步),将上一步(第 2 步)所放置的皇‎后的位置再‎重新取走放‎在另一个符‎合要求的地‎方…如此尝试性‎地遍历加上‎回溯,就可以慢慢‎地逼近最终‎解了。

2、需要解决的‎问题:如何表示一‎个N * N 方格棋盘能‎够更有效?怎样测试当‎前所走的试‎探路径是否‎符合要求?这两个问题‎都需要考虑‎到使用怎样‎的数据结构‎,使用恰当的‎数据结构有‎利于简化编‎程求解问题‎的难度。

3、我们使用以‎下的数据结‎构:int colum‎n[col] = row 表示第 col 列的第 row 行放置一个‎皇后boole‎an rowEx‎i sts[i] = true 表示第 i 行有皇后boole‎an a[i] = true 表示右高左‎低的第 i 条斜线有皇‎后(按→↓顺序从1~ 2*N -1 依次编号)boole‎an b[i] = true 表示左高右‎低的第 i 条斜线有皇‎后(按→↑顺序从1~ 2*N -1 依次编号)五、算法实现对应这个数‎据结构的算‎法实现如下‎:1.**2. * 回溯法求解‎N 皇后问题3. * @autho‎r haoll‎o yin4. */5.publi‎c class‎N_Que‎e ns {6.7.// 皇后的个数‎8. priva‎t e int queen‎s Num = 4;9.10.// colum‎n[i] = j表示第 i 列的第 j 行放置一个‎皇后11. priva‎t e int[] queen‎s = new int[queen‎s Num + 1];12.13.// rowEx‎i sts[i] = true 表示第 i 行有皇后14. priva‎t e boole‎a n[] rowEx‎i sts = new boole‎a n[queen‎sNum + 1];15.16.// a[i] = true 表示右高左‎低的第 i 条斜线有皇‎后17. priva‎t e boole‎a n[] a = new boole‎a n[queen‎s Num * 2];18.19.// b[i] = true 表示左高右‎低的第 i 条斜线有皇‎后20. priva‎t e boole‎a n[] b = new boole‎a n[queen‎s Num * 2];21.22.// 初始化变量‎23. priva‎t e void init() {24. for (int i = 0; i < queen‎s Num + 1; i++) {25. rowEx‎i sts[i] = false‎;26. }27.28. for(int i = 0; i < queen‎s Num * 2; i++) {29. a[i] = b[i] = false‎;30. }31. }32.33.// 判断该位置‎是否已经存‎在一个皇后‎,存在则返回‎true34. priva‎t e boole‎a n isExi‎s ts(int row, int col) {35. retur‎n (rowEx‎i sts[row] || a[row + col - 1]|| b[queen‎s Num + col - row]);36. }37.38.// 主方法:测试放置皇‎后39. publi‎c void testi‎n g(int colum‎n) {40.41.// 遍历每一行‎42. for (int row = 1; row < queen‎s Num + 1; row++) {43.// 如果第 row 行第 colum‎n列可以放置‎皇后44. if (!isExi‎s ts(row, colum‎n)) {45.// 设置第 row 行第 colum‎n列有皇后46. queen‎s[colum‎n] = row;47.// 设置以第 row 行第 colum‎n列为交叉点‎的斜线不可‎放置皇后48. rowEx‎i sts[row] = a[row + colum‎n - 1] = b[queen‎s Num + colum‎n - row] = true;49.50.// 全部尝试过‎,打印51. if(colum‎n == queen‎s Num) {52. for(int col = 1; col <= queen‎s Num; col++) {53. Syste‎m.out.print‎("("+col +"," + queen‎s[col] + ") ");54. }55. Syste‎m.out.print‎l n();56. }else {57.// 放置下一列‎的皇后58. testi‎n g(colum‎n + 1);59. }60.// 撤销上一步‎所放置的皇‎后,即回溯61. rowEx‎i sts[row] = a[row + colum‎n - 1] = b[queen‎s Num + colum‎n - row] = false‎;62. }63. }64. }65.66.//测试67. publi‎c stati‎c void main(Strin‎g[] args) {68. N_Que‎e ns queen‎= new N_Que‎e ns();69. queen‎.init();70.// 从第 1 列开始求解‎71. queen‎.testi‎n g(1);72. }73.}六、运行结果当N = 8 时,求解结果如‎下(注:横坐标为列数,纵坐标为行数):(1,1) (2,5) (3,8) (4,6) (5,3) (6,7) (7,2) (8,4)1.(1,1) (2,6) (3,8) (4,3) (5,7) (6,4) (7,2) (8,5)2.(1,1) (2,7) (3,4) (4,6) (5,8) (6,2) (7,5) (8,3)3.... ...4.... ...5.(1,8) (2,2) (3,4) (4,1) (5,7) (6,5) (7,3) (8,6)6.(1,8) (2,2) (3,5) (4,3) (5,1) (6,7) (7,4) (8,6)7.(1,8) (2,3) (3,1) (4,6) (5,2) (6,5) (7,7) (8,4)8.(1,8) (2,4) (3,1) (4,3) (5,6) (6,2) (7,7) (8,5)当N = 4 时,求解结果如‎下:1.(1,2) (2,4) (3,1) (4,3)2.(1,3) (2,1) (3,4) (4,2)七、实验小结:1、根据问题选‎择恰当的数‎据结构非常‎重要,就像上面 a 、b 标志数组来‎表示每一条‎斜线的编号‎顺序以及方‎向都相当重‎要。

n皇后 实验报告

n皇后 实验报告

n皇后实验报告n皇后实验报告引言:n皇后问题是一个经典的数学问题,旨在找到在一个n×n的棋盘上放置n个皇后,使得它们互不攻击。

这个问题涉及到了组合数学、图论和计算机算法等多个领域,具有一定的难度和挑战性。

本实验旨在通过不同的算法和策略来解决n皇后问题,并对它们的效率和性能进行评估。

实验一:暴力法暴力法是最简单直接的解决方法之一。

它通过穷举法遍历所有可能的皇后放置方式,并检查是否满足条件。

具体步骤如下:1. 生成一个空的n×n棋盘。

2. 从第一行开始,依次尝试将皇后放置在每个格子上。

3. 如果当前格子可以放置皇后,则继续下一行;否则,回溯到上一行,重新选择一个可行的格子。

4. 当所有行都放置了皇后时,找到了一个解,记录下来。

5. 继续尝试下一个可能的放置方式,直到遍历完所有情况。

实验结果显示,暴力法在小规模问题上表现良好,但在n较大时,其时间复杂度呈指数级增长,运行时间非常长。

实验二:回溯法回溯法是一种优化的解决方法,它通过剪枝操作来减少不必要的搜索。

具体步骤如下:1. 生成一个空的n×n棋盘。

2. 从第一行开始,依次尝试将皇后放置在每个格子上。

3. 如果当前格子可以放置皇后,则继续下一行;否则,回溯到上一行,重新选择一个可行的格子。

4. 当所有行都放置了皇后时,找到了一个解,记录下来。

5. 在每次尝试放置皇后时,通过检查当前格子所在的行、列和对角线上是否已经有皇后,来判断是否满足条件。

6. 在每次回溯时,可以通过剪枝操作来减少搜索的空间。

实验结果显示,回溯法相较于暴力法有了一定的提升,但在n较大时,仍然存在一定的时间复杂度问题。

实验三:优化算法为了进一步提高解决n皇后问题的效率,我们尝试了一些优化算法。

其中,一种比较常见的优化算法是基于位运算的方法。

1. 生成一个空的n×n棋盘。

2. 使用一个n位的二进制数来表示每一行上的皇后位置,其中1表示有皇后,0表示没有皇后。

迭代回溯法法实现N皇后问题

迭代回溯法法实现N皇后问题

package nqueen;import java.util.Scanner;/*** 程序目的:用迭代回溯法解决N-皇后问题** 作者:孙松山** 制作日期:2011-11-15*/public class NQueen {private int N = 65535; // 问题规模// 问题的规模(注意:此处必须要定义一个数值,因为在下一句数组的定义时要用到此数字,否则报错)private int[] x = new int[N + 1]; // 第k行的第x[k]列private int count; // 存放有多少种解法/*** 设置问题的规模** @param n*/public void setN(int n) {N = n;}/*** 得到N的值** @return*/public int GetN() {return N;}/*** 得到总共有多少种解法的值** @return*/public int GetCount() {return count;}/*** 判断此位置是否安全(不和前边已经放置的皇后在同一列或者对角线上)** @param row* @return*/private boolean SafeQueen(int row) {int i;for (i = 1; i < row; i++)if (x[i] == x[row] || i - x[i] == row - x[row]|| i + x[i] == row + x[row])return false;return true;}/*** 深度优先遍历整个解空间*/public void Queen() {int i, j;int k = 1;x[1] = 1;count = 0;// 当k值减为0时则遍历完毕while (k > 0) {// 如果此列不安全,则遍历下一列,直到遍历完此行的每一列为止while (x[k] <= N && !SafeQueen(k)) {x[k]++;}if (x[k] <= N) {if (k == N) {for (i = 1; i <= N; i++) {// 控制棋盘的输出for (j = 1; j <= N; j++) {if (j == x[i])System.out.print('Q' + " ");elseSystem.out.print('-' + " ");}System.out.println();}count++;System.out.println("\n*************************\n");// 找到一个最优解之后,回溯k--;x[k]++;} else {// 正常情况下向下遍历k++;x[k] = 1;}} else {// 当遍历k行的每一列都没有解时,回溯到k-1行,并且从第x[k-1]+1列再次开始遍历k--;x[k]++;}}}/*** 主函数** @param args* @throws IOException* @throws NumberFormatException*/public static void main(String[] args) {NQueen q = new NQueen();int n;// 输入问题的规模数据System.out.print("请输入问题的规模:");Scanner cin = new Scanner(System.in);n = cin.nextInt();q.setN(n);System.out.println("以下为" + q.GetN() + "-皇后问题的所有解:");long start = System.currentTimeMillis();// 获得程序开始执行时的时间q.Queen();long end = System.currentTimeMillis();// 获得程序结束时的时间System.out.println("Time:" + (end - start));System.out.println(q.GetN() + "-皇后问题的解法共有:" + q.GetCount() + "种");}}。

n皇后 实验报告

n皇后 实验报告

n皇后问题实验报告1. 引言n皇后问题是一个经典的组合优化问题,旨在找到如何在一个n × n的棋盘上放置n个皇后,使得任意两个皇后不在同一行、同一列或同一对角线上。

这个问题可以通过回溯算法来解决。

在本实验报告中,我们将详细介绍n皇后问题,并提供一个实现回溯算法解决该问题的步骤。

2. 算法步骤以下是解决n皇后问题的步骤:2.1 初始化首先,我们需要定义一个n × n的棋盘,并初始化所有位置为空。

2.2 递归回溯接下来,我们使用递归回溯来找到合适的解决方案。

我们从第一行开始,逐个尝试在每个位置放置一个皇后。

2.2.1 判断位置是否合法在放置皇后之前,我们需要判断当前位置是否符合规则。

判断的条件包括当前位置所在的行、列以及对角线上是否已经存在其他皇后。

如果存在冲突,则需要尝试下一个位置。

2.2.2 放置皇后如果当前位置合法,我们将在该位置放置一个皇后,并继续递归地尝试下一行。

2.2.3 回溯如果放置皇后后无法找到合适的解决方案,我们需要回溯到上一行,将上一行的皇后位置向后移动一位,并尝试下一个位置。

2.3 输出解决方案当找到一个合适的解决方案时,我们输出棋盘的状态,显示每个位置是否有皇后。

2.4 继续寻找其他解决方案如果还存在其他解决方案,我们将继续递归回溯,直到找到所有的解决方案。

3. 实验结果经过实验,我们使用回溯算法成功解决了n皇后问题。

对于不同的n值,我们找到了所有的解决方案并进行了输出。

以下是几个n皇后问题的解决方案示例:3.1 n = 4- Q - -- - - QQ - - -- - Q -3.2 n = 8Q - - - - - - -- - - - Q - - -- - - - - - - Q- - - - - Q - -- - Q - - - - -- - - - - - Q -- Q - - - - - -- - - Q - - - -4. 总结通过本实验,我们了解了n皇后问题,并学习了回溯算法的应用。

5-4回溯法-皇后好累

5-4回溯法-皇后好累

要求在一个n×n的棋盘上放置n个皇后,使得她们彼此不受攻击。

八皇后问题求解过程第1列第2列第3列第4列第5列第6列第7列第1行第2行第3行第4行第5行第6行第7行第8行八皇后的一个可行解第1列第2列第3列第4列第5列第6列第7列第1行○第2行○第3行○第4行第5行○第6行○第7行○第8行○先回顾递归回溯法的一般形式:NTry(s)做挑选候选者的准备;while (未成功且还有候选者) {挑选下一个候选者next ;if (next 可接受) {记录next ;if (满足成功条件) {成功并输出结果}else Try(s+1);if (不成功) 删去next 的记录; }}return 成功与否}NTry(s){做挑选候选者的准备;while (未成功且还有候选者) {挑选下一个候选者next ;if (next 可接受) {记录next ;if (满足成功条件) {成功并输出结果}else Try(s+1);if (不成功) 删去next 的记录; }}return 成功与否}s 为准备放置后的行数候选者为1到n 列。

j = 0; q = 0; 令列标记j = 0;q 表示未成功。

列数不到n 就还有候选者(!q && j < n ) { 列数加1j++;各后都安全,便可接受(Safe(s, j)) {记下该行后的位置(列数)Record(s, j);n 行后都放完就成功了(s = = n) {q = 1; output( );} 不成功,删去后在该行的位置。

(!q) Move-Off(s, j); }}}q }数组B[n]表示棋盘。

若B[i]=j ,1≤i, j≤n ,表示棋盘的第i 行第j 列上有皇后。

N数组C[j]=1表示第j 列上无皇后,1≤j≤n 。

数组D[k]=1表示第k 条下行(↘)对角线上无皇后。

123456123456k = i + j ,2≤k≤2n 。

n后问题 回溯法

n后问题 回溯法

实验四 n后问题一.实验目的1. 了解皇后相互攻击的条件:如果任意两个皇后在同一行,同一列或同一对角线,则她们相互攻击。

2. 运用迭代的方法实现n皇后问题,求解得到皇后不相互攻击的一个解二.实验内容基本思路:用n元组x[1:n]表示n后问题的解,其中x[i]表示第i个皇后放在棋盘的第i 行的第x[i]列。

抽象约束条件得到能放置一个皇后的约束条件:(1)x[i]!=x[k];(2)abs(x[i]-x[k])!=abs(i-k)。

应用回溯法,当可以放置皇后时就继续到下一行,不行的话就返回到第一行,重新检验要放的列数,如此反复,直到将所有解解出。

在回溯法中,递归函数Backtrack(1)实现对整个解空间的回溯搜索。

Backtrack(i)搜索解空间的第i层子树。

类Queen 的数据成员记录解空间的节点信息,以减少传给Backtrack函数的参数。

sum记录当前已找到的可行方案数。

运用回溯法解题通常包含以下三个步骤:(1)针对所给问题,定义问题的解空间;(2)确定易于搜索的解空间结构;(3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

三.实验结果四.源代码:#include<iostream>#include<stdlib.h>using namespace std;class Queen{friend int nQueen(int);private:bool Place(int k);void Backtract(int t);int n,*x;long sum; //可行方案数};bool Queen::Place(int k){for(int j=1;j<k;j++)if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) return false;return true;}void Queen::Backtract(int t){if (t>n){sum++;cout<<"第"<<sum<<"种方法:";for(int i=1;i<=n;i++)cout<<x[i]<<" ";cout<<endl;}else{for(int i=1;i<=n;i++){x[t]=i;if(Place(t)) Backtract(t+1);}}}int nQueen(int n){Queen X;X.n=n;X.sum=0;int *p=new int[n+1];for(int i=0;i<=n;i++)p[i]=0;X.x=p;X.Backtract(1);delete []p;return X.sum;}void main(){int n,m;cout<<"请输入皇后个数:";cin>>n;m=nQueen(n);cout<<endl;cout<<"有"<<m<<"种可行方法"<<endl;system("pause");}。

回溯法之N皇后问题

回溯法之N皇后问题

回溯法之N皇后问题回溯法之N皇后问题1. 问题描述在n*n格的棋盘上放置彼此不受攻击的n个皇后。

按照国际象棋的规则,皇后可以攻击与之在同⼀⾏或同⼀列或同⼀斜线上的旗⼦。

n后问题等价于在n*n格的棋盘上放置n个皇后,任何2个皇后不放在同⼀⾏或同⼀列或同⼀斜线上。

2. 问题分析(以n=4皇后问题为例)有俩种解法,第⼀种采⽤解空间为N(4)叉树的解法、第⼆种是采⽤解空间为排列数的解法。

2.1. N(4)叉树的解法每个皇后在⼀⾏上有四个可选位置。

即每个⾮叶结点有4个⼦节点,4叉树如下:解向量:(x1,x2,x3,......,x n)显约束:任意俩皇后不同⾏。

隐约束:(1) 不同列:x i ≠ x j (2) 不处于同⼀正反对⾓线:|i - j| ≠ |x i - x j|核⼼代码:// 剪枝函数,排除同列和同⼀对⾓线的分⽀int place1(int k) {for (int j = 1; j < k; j++)if (abs(k - j) == abs(x[j] - x[k]) || x[j] == x[k])return 0;return 1;}// t > n代表当前解已经求出,将总数+1// 利⽤循环遍历节点的n叉,同时判断分叉是否符合条件// 符合条件的分叉继续遍历下去void BackTrack1(int t) {if (t > n)sum++;elsefor (int i = 1; i <= n; i++) {x[t] = i;if (place1(t))BackTrack1(t + 1);}}2.2 排列数的解法解向量:(x1,x2,x3,......,x n)显约束:任意俩皇后不同⾏、不同列。

x1,x2,x3,......,x n是1,2,3.......n排列隐约束:不处于同⼀正反对⾓线:|i - j| ≠ |x i - x j|核⼼代码:// 交换俩⾏皇后的位置// 实现切换排列数的分⽀作⽤void swap(int i, int j) {int tmp = x[i];x[i] = x[j];x[j] = tmp;}// 剪枝函数,排除在同⼀对⾓线上的情况int place2(int k) {for (int j = 1; j < k; j++)if (abs(k - j) == abs(x[j] - x[k]))return 0;return 1;}// t > n时表⽰当前排列符合条件,总数 + 1// 利⽤for循环,和swap函数,将节点对应的所有排列遍历⼀次// 同时采⽤剪枝函数,减去错误的分⽀// 对正确的分⽀继续求解下去// 最后递归求解结束后,再次调⽤swap函数将状态返回到原本的节点状态void BackTrack2(int t) {if (t > n) sum++;elsefor (int i = t; i <= n; i++) {swap(t, i);if (place2(t))BackTrack2(t + 1);swap(t ,i);}}3. 完整代码/*** 回溯法求解n皇后问题* 使⽤x解向量,x1,x2,x3分别表⽰在1,2,3⾏上皇后的列号**/#include <stdio.h>#include <stdlib.h>#define MAX 4/*** n 皇后个数* x 当前解* sum**/int n = MAX;int x[MAX + 1];long sum = 0;// 剪枝函数,排除同列和同⼀对⾓线的分⽀int place1(int k) {for (int j = 1; j < k; j++)if (abs(k - j) == abs(x[j] - x[k]) || x[j] == x[k])return 0;return 1;}// t > n代表当前解已经求出,将总数+1// 利⽤循环遍历节点的n叉,同时判断分叉是否符合条件// 符合条件的分叉继续遍历下去void BackTrack1(int t) {if (t > n)sum++;elsefor (int i = 1; i <= n; i++) {x[t] = i;if (place1(t))BackTrack1(t + 1);}}// 交换俩⾏皇后的位置// 实现切换排列数的分⽀作⽤void swap(int i, int j) {int tmp = x[i];x[i] = x[j];x[j] = tmp;}// 剪枝函数,排除在同⼀对⾓线上的情况int place2(int k) {for (int j = 1; j < k; j++)if (abs(k - j) == abs(x[j] - x[k]))return 0;return 1;}// t > n时表⽰当前排列符合条件,总数 + 1// 利⽤for循环,和swap函数,将节点对应的所有排列遍历⼀次// 同时采⽤剪枝函数,减去错误的分⽀// 对正确的分⽀继续求解下去// 最后递归求解结束后,再次调⽤swap函数将状态返回到原本的节点状态void BackTrack2(int t) {if (t > n) sum++;elsefor (int i = t; i <= n; i++) {swap(t, i);if (place2(t))BackTrack2(t + 1);swap(t ,i);}}void main() {for (int i = 0; i <= n; i++)x[i] = i;BackTrack1(1);printf("%d\n", sum);for (int i = 0; i <= n; i++)x[i] = i;sum = 0;BackTrack2(1);printf("%d\n", sum);system("pause");}。

回溯法解决n皇后问题

回溯法解决n皇后问题

n 皇 后 问 题N 皇后问题,是一个古老而着名的问题,是回溯算法的典型例题:在N*N 格的格子上摆放N 个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法? 1、定义问题的解空间首先以八皇后为例,可以用一棵树表示8皇后问题的解空间。

由于8皇后问题的解空间为8!种排列,因此我们将要构造的这棵树实际上是一棵排列树。

2、确定解空间树的结构给棋盘上的行和列从1到8编号,同时也给皇后从1到8编号。

由于每一个皇后应放在不同的行上,不失一般性,假设皇后i 放在第i 行上,因此8皇后问题可以表示成8元组(x 1, x 2, …, x 8), 其中xi (i =1, 2, …, 8)表示皇后i 所放置的列号。

这种表示法的显式约束条件是S i ={1, 2, 3, 4, 5, 6, 7, 8},i =1, 2, …, 8。

在这种情况下, 解空间为88个8元组组成,而隐式约束条件是没有两个xi 相同(即所有皇后必须在不同列上),且满足不存在两个皇后在同一条对角线上。

加上隐式约束条件,问题的解空间可进一步减小。

此时,解空间大小为8!,因为所有解都是8元组的一个置换。

图5-7表示了8皇后问题的一个解。

图5-7 8皇后问题的一个解为了简单起见,图5-8只给出了n =4时问题的一种可能树结构。

QQQQQQQQ8765432112345678图5-8 4皇后问题解空间的树结构在实际中,并不需要生成问题的整个状态空间。

通过使用限界函数来删除那些还没有生成其所有子结点的活结点。

如果用(x1,x2,…,x i)表示到当前E结点的路径,那么xi+1就是这样的一些结点,它使得(x1,x2,…,x i,x i+1)没有两个皇后处于相互攻击的棋盘格局。

在4皇后问题中,惟一开始结点为根结点1,路径为( )。

开始结点既是一个活结点,又是一个E结点,它按照深度优先的方式生成一个新结点2,此时路径为(1),这个新结点2变成一个活结点和新的E结点,原来的E结点1仍然是一个活结点。

回溯算法实验报告

回溯算法实验报告
}
}
void main()
{
c=new int[n+1];
ofstream outfile;
outfile.open("output.txt",ios::app);//创建output文件
outfile<<n<<"皇后问题"<<endl;
search(1);//由第一行开始搜索
outfile.close();
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>
实验日期及节次
2012-2-20
一、问题描述
n后问题是指在一个n*n的棋盘上放置n个皇后,使得它们彼此不受攻击。而一个皇后可以攻击与它处在同一行或同一列或同一斜线上的任何棋子。故n后问题可以理解为:在一个n*n的棋盘内放置n个皇后,使任意两个皇后不处在同一行或同一列或同一斜线上。
在这个问题中,我用了一个n*n的数组来存储棋盘,由于n后问题的典型是8皇后问题,所以我做的是8皇后问题。得出的解以以下形式出现在文件中:
else
for(i=1;i<=n;i++)//按列搜索
{
bool ok=1;
c[cur]=i; //尝试将第cur行的皇后放入第i列
for(j=1;j<cur;j++)//检测是否与前cur-1行的皇后有冲突
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法分析与设计实验报告第三次附加实验
附录:
完整代码(回溯法)
//回溯算法递归回溯n皇后问题#include<iostream>
#include<time.h>
#include<iomanip>
#include"math.h"
using namespace std;
class Queen
{
friend int nQueen(int); //定义友元函数,可以访问私有数据
private:
bool Place(int k); //判断该位置是否可用的函数
void Backtrack(int t); //定义回溯函数
int n; //皇后个数
int *x; //当前解
long sum; //当前已找到的可行方案数
};
int main()
{
int m,n;
for(int i=1;i<=1;i++)
{
cout<<"请输入皇后的个数:"; //输入皇后个数
cin>>n;
cout<<"皇后问题的解为:"<<endl;
clock_t start,end,over; //计算程序运行时间的算法
start=clock();
end=clock();
over=end-start;
start=clock();
m=nQueen(n); //调用求解的函数
cout<<n<<"皇后问题共有";
cout<<m<<"个不同的解!"<<endl; //输出结果
end=clock();
printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运行时间
cout<<endl;
}
system("pause");
return 0;
}
bool Queen::Place(int k)//传入行号
{
for(int j=1;j<k;j++)
{
if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))//如果两个在同一斜线或者在同一列上,说明冲突,该位置不可用
{
return false;
}
}
return true;
}
void Queen::Backtrack(int t)
{
if(t>n)
{
sum++;
/*for(int i=1;i<=n;i++) //输出皇后排列的解
{
cout<<x[i]<<" ";
}
cout<<endl;*/
}
else
{//回溯探索第i行的每一列是否有元素满足要求for(int i=1;i<=n;i++)
{
x[t]=i;
if(Place(t))
{
Backtrack(t+1);
}
}
}
}
int nQueen(int n)
{
Queen X; //定义Queen类的对象X
//初始化X
X.n=n;
X.sum=0;
int *p=new int[n+1]; //动态分配
for(int i=0;i<=n;i++) //初始化数组
{
p[i]=0;
}
X.x=p;
X.Backtrack(1);
delete[] p;
return X.sum;//输出解的个数
}
完整代码(回溯法)
//回溯算法迭代回溯n皇后问题
#include<iostream>
#include<time.h>
#include<iomanip>
#include"math.h"
using namespace std;
class Queen
{
friend int nQueen(int); //定义友元函数
private:
bool Place(int k); //定义位置是否可用的判断函数
void Backtrack(void); //定义回溯函数
int n; // 皇后个数
int *x; // 当前解
long sum; // 当前已找到的可行方案数
};
int main()
{
int n,m;
for(int i=1;i<=1;i++)
{
cout<<"请输入皇后的个数:";
cin>>n;
cout<<n<<"皇后问题的解为:"<<endl;
clock_t start,end,over; //计算程序运行时间的算法
start=clock();
end=clock();
over=end-start;
start=clock();
m=nQueen(n); //调用求解皇后问题的函数
cout<<n<<"皇后问题共有";
cout<<m<<"个不同的解!"<<endl;
end=clock();
printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运
行时间
cout<<endl;
}
system("pause");
return 0;
}
bool Queen::Place(int k)
{
for (int j=1;j<k;j++)
{
if ((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) //如果两个皇后在同一斜线或者在同一列上,说明冲突,该位置不可用
{
return false;
}
}
return true;
}
void Queen::Backtrack() //迭代法实现回溯函数
{
x[1] = 0;
int k = 1;
while(k>0)
{
x[k] += 1; //先将皇后放在第一列的位置上
while((x[k]<=n)&&!(Place(k))) //寻找能够放置皇后的位置
{
x[k] += 1;
}
if(x[k]<=n) //找到位置
{
if(k == n) //如果寻找结束输出结果
{
/*for (int i=1;i<=n;i++)
{
cout<<x[i]<<" ";
}
cout<<endl; */
sum++;
}
else//没有结束则找下一行
{
k++;
x[k]=0;
}
}
else//没有找到合适的位置则回溯
{ k--; }
}
}
int nQueen(int n)
{
Queen X; //定义Queen类的对象X
//初始化X
X.n=n;
X.sum=0;
int *p=new int[n+1];
for(int i=0;i<=n;i++)
{
p[i]=0;
}
X.x=p;
X.Backtrack();
delete []p;
return X.sum; //返回不同解的个数
}。

相关文档
最新文档