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; //返回不同解的个数}。

实验十 n皇后问题

实验十  n皇后问题

算法设计与分析实验报告姓名:杨勇涛班级:计科102一、实验名称:n皇后问题时间:2012年4月25日,星期三,第四节地点:12#311二、实验目的及要求在n*n格的棋盘上放置彼此不受攻击的n皇后。

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

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

三、实验环境VC++四、实验内容从键盘上输入n皇后的数目,输出所有的结果五、算法描述及实验步骤N×N皇后问题的求解过程就是一个试探回逆的过程。

如图-1(图1-1)1、首先查找第一行的可放位置,第一行全部可以放,那么我们就先将第一个皇后放在(0,0)点。

(图1-2)2、再查找第二行,由于第一行的(0,0)已经放了皇后,故第二行的(1,0)和(1,1)都能放皇后了,可放的就是(1,2)和(1,3)点,在(1,2)放上皇后。

(图1-3)3、再查找第三行,查找所以发现第三行没有可放的位置了,回逆到第二行讲皇后放到(1,3)再查找第3行。

如果还不行,就回到第一行将第一行的皇后放人下一个可放的点,依次类推,查找N×N上的所以可放的位置,直到第一行所以位置被放完,输出结果。

4、根据上面的规律可以发现,对于一个皇后放在坐标(x,y),它的下一行位置为(x-1,y)(x,y)(x+1,y)的坐标都不能再放皇后。

我们用一个数组来存放本行能放皇后的点。

用循环来查找上面行对本行的影响六、调试过程及实验结果七、总结回溯法有“通用的解题法”之称。

用它可以系统的搜索一个问题的所有解或任一解。

回溯法是一个既带有系统性又带有跳跃性的搜索算法。

八、附录(源程序清单)#include "math.h"#include <iostream>using namespace std;bool valid(int i,int j);//判断安置元素的合法性void trial(int i); //递归安置元素void print(); //显示布局int q; //皇后数int *a; //存储布局元素int count = 0; //合法布局的序号int main(int argc, char* argv[]){cout<<"请输入皇后数:"<<endl;cin>>q;a = new int[q*q];for(int j=0;j<q*q;j++)a[j] = 0;trial(0);cout<<"布局完毕"<<endl;return 0;}void trial(int i) //递归安置元素{if(i>=q)print();elsefor(int j=0;j<q;j++){a[i*q+j] = 1;if(valid(i,j))trial(i+1);a[i*q+j] = 0;}}bool valid(int i,int j) //判断安置元素的合法性{bool b=true;for(int i1=0;i1<i;i1++)for(int j1=0;j1<q;j1++)if(a[i1*q+j1]==1){if(j1==j)//判断是否在同一列b = false;else if(abs(i-i1)==abs(j-j1))//判断是否在对角线b = false;}return b;}void print() //显示布局{count++;cout<<"第"<<count<<" 种布局:"<<endl;for(int m=0;m<q;m++){for(int n=0;n<q;n++){cout<<a[m*q+n]<<" ";}cout<<endl;}cout<<"----------------------------------------"<<endl; }。

n皇后 实验报告

n皇后 实验报告

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

(完整word版)N皇后问题实验报告

(完整word版)N皇后问题实验报告

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

2.运用迭代的方法实现6皇后问题,求解得到皇后不相互攻击的一个解。

3.在运用迭代的方法实现编程时,要注意回溯点。

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

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

四、具体实现package queen;import java.util.Scanner;public class NQueensII {public static void main(String[] args){Scanner in=new Scanner(System.in);System.out.println("Please enter the number of queen you want(请输入你要求解的皇后的个数)");int n=in.nextInt();Queen(n);}/***用回溯法设计函数Queen(n)求解*/public static boolean Place(int x[],int k)//考察皇后k放置在x[k]列是否发生冲突{for(int i=1; i<k; i++)if (x[k]==x[i]||Math.abs(k-i)==Math.abs(x[k]-x[i])) return false;return true;}public static void Queen(int n){int x[]=new int[n+1];for (int i=1; i<=n; i++)//初始化x[i]=0;int k=1;while (k>=1){x[k]=x[k]+1;//在下一列放置第k个皇后while (x[k]<=n&&!Place(x,k))x[k]=x[k]+1;//搜索下一列if (x[k]<=n && k==n){ //得到一个解,输出System.out.println("The answer is(得到的解是):");for (int i=1; i<=n; i++)System.out.print("("+i+","+x[i]+")"+" ");System.out.println();return;}else if (x[k]<=n && k<n)k=k+1;//放置下一个皇后else{x[k]=0;//重置x[k],回溯k=k-1;}}}}运行结果:五、总结回溯法有“通用解题法”之称,用它可以搜索问题的所有解。

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皇后问题实验报告

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<<" 种放置方法。

实验报告:回溯法求解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皇后问题算法实验报告

算法分析与设计实验报告实验内容:N皇后问题实验时间:2013.12.3姓名:***班级:计科1101学号:**********一、实验内容及要求在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皇后

局部搜索实验之N皇后

300万个皇后6秒钟
PB07210134 高航
实验目的:
用局部搜索算法尽可能快的解决N皇后问题
实验过程
1.问题的表示:一个数组queen[i]存放第i列皇后的行数
confilict:冲突数
2.自己动手按照书上的算法写
发现每步复杂度是O(N2)难以承受。

3.简化问题。

构造初始状态时,用洗牌的想法构造出一个没有行冲突的状态,之后对此状态进行列交换。

4.参阅《300,000,000 Queens in Less Than One Minute》一文学到了QS4算
法,并了解到之前采用的是QS1算法。

彻底解决了该问题。

QS4算法主要是在生成初始状态方面进行了改进,以便尽可能的减少初始状态的冲突。

5.实验结果:
时间复杂度达到O(N)
为保证算法的正确性,另写有一check.exe检查输出文件的正确。

文件:
QS4.cpp
check.exe
《300,000,000 Queens in Less Than One Minute》。

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皇后问题,并学习了回溯算法的应用。

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<<" 种放置方法。

n皇后问题和罗马尼亚问题实习报告

n皇后问题和罗马尼亚问题实习报告

人工智能课程实习报告题目:n皇后问题和罗马尼亚问题班号:191122 学号:20121003553姓名:叶超指导老师:赵曼2014.11目录人工智能课程实习报告 (1)目录 (2)罗马尼亚问题 (4)一、问题描述 (4)二、图的数据结构 (5)三、实现算法 (5)1.宽度优先 (5)1.1数据结构: (5)1.2算法思想: (6)1.3运行结果: (6)2.深度优先 (7)2.1数据结构: (7)2.2算法思想: (7)2.3运行结果: (7)3.贪婪算法 (8)3.1数据结构: (8)3.2算法思想: (8)3.3运行结果: (8)4.A*算法 (9)4.1数据结构: (9)4.2算法思想: (9)4.3运行结果: (9)四、比较结论 (10)N皇后问题 (11)一、问题描述: (11)二、数据结构 (12)三、实现算法 (12)1、回溯法 (12)1.1数据结构: (12)1.2算法思想: (12)1.3运行结果: (13)2、遗传算法 (13)2.1数据结构: (13)2.2算法思想: (13)2.3运行结果 (14)3、CSP最小冲突法 (14)3.1数据结构: (14)3.2算法思想: (14)3.3运行结果: (15)四、比较结论 (15)总结 (16)附源代码 (16)罗马尼亚问题 (16)N皇后问题 (27)递归算法 (27)遗传算法 (30)csp 最小冲突法 (35)罗马尼亚问题一、问题描述(1)罗马尼亚问题:Find Bucharest starting at Arad分别用宽度优先、深度优先、贪婪算法和A*算法求解“罗马利亚度假问题”。

要求:分别用文件存储地图和启发函数表,用生成节点数比较几种算法在问题求解时的效率,列表给出结果。

(2)附(罗马尼亚地图)(3)(3)各结点启发值:二、图的数据结构(1)节点信息:typedef struct{char cityname[20];//城市名int value; //启发函数值int cost; //路径花费}Ver;(2)地图信息typedef struct{Ver V[MaxV];//一维城市数组int edge[MaxV][MaxV];//二维边数组int numofedges;}Graph;(3)图的操作函数void Read_V(Graph &G);//从文件读取顶点信息void Read_edge(Graph &G);//从文件读取边的信息int GetFirstV(Graph G,int v);//取节点v的第一个子节点int GetNextV(Graph G,int v1,int v2);//取节点v1子节点v2后的第一个子节点三、实现算法1.宽度优先1.1数据结构:队列(BFS,贪婪,A*公用)typedef struct{int queue[MaxSize];int rear;int front;int count;} SeqCQuene;队列操作:void QueueInitiate(SeqCQuene *Q);int QueueNotEmpty(SeqCQuene Q);int QueueDelete(SeqCQuene *Q,int *d);int QueueAppend(SeqCQuene *Q,int x);//先进先出(BFS)记录父亲用于打印路径typedef struct{int father;int me;}way;1.2算法思想:从Arad结点出发,判断是否为目标结点,若否,宽度优先搜索系统地探寻与该结点相连的结点,算法首先搜索和Arad相距(深度)为k的所有顶点,然后再去搜索和Arad相距为k+l的其他顶点,找出并存进待扩展结点表,等待扩展,每次先判断待扩展结点表是否为空,若否则从待扩展结点表中取出一个结点进行扩展,并将扩展后的结点存进该表,若是,则返回失败。

n皇后的实验报告

n皇后的实验报告

09级计算机科学与技术2班组长:郭惠芝40912091小组成员:席菲菲40912098闫卫红40912099王铝红40912103回溯法----------n皇后问题王铝红,郭惠芝,席菲菲,闫卫红(陕西师范大学计算机科学学院陕西西安710062)摘要:文章中对“八皇后问题”进行了分析,给出了一种回溯算法解决“八皇后问题”并用C++语言实现,从而上升为对“n皇后问题”的解决。

关键字:回溯法,八皇后问题,算法,实现Eight Queens PuzzleAbstract: Article in the “Eight Queens Puzzle” issues were analyzed and given an iteration method to solve “Eight Queen Puzzle” and use C ++ language implementation.Keywords:Iteration method , Eight Queens Puzzle, Algorithm, Implementation中心内容:1、问题描述八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。

该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

高斯认为有76种方案。

1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论比较特殊的是,皇后6x6棋盘的解比5 x 5少,其余解的数目随着皇后数目增加。

但似乎无数学表达式可以描述。

2、模型建立下面以8皇后为例建立模型,让大家更清楚的理解n皇后问题。

不妨设8个皇后为X i,她们分别在第i行(i=1,2,3,4,…,8),这样问题的解空间,就是一个8个皇后所在列的序号,为n元一维向量(X1 ,X2 ,X3,X4,X5 ,X6 ,X7 ,X8),搜索空间是1≦X i≦8(i=1,2,3,4,…,8),共88个状态。

N皇后问题实验报告

N皇后问题实验报告

N皇后问题实验报告电子工程学院A.实验内容在n×n格的棋盘上放置彼此不受攻击的n个皇后,按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子,求解可以放置的方法种数。

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

即规定每一列放一个皇后,不会造成列上的冲突;当第i 行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以i为下标的标记置为被占领状态。

C.算法设计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)1 / 6{if(k==n)Print(x,n);else{k=k+1;x[k]=0;}}//回溯至上一行;elsek--;}}3. 实验结果及分析n皇后问题解的情况皇后的个问题的解数N=1 X=(1) N=2 无解N=3 无解N=4 X1=(2,4,1,3); X2=(3,1,4,2) N=5 X1=(1,3,5,2,4); X2=(1,4,2,5,3); X3=(2,4,1,3,5);X4=(2,5,3,1,4);X5=(3,1,4,2,5); X6=(3,5,2,4,1); X7=(4,1,3,5,2);X8=(4,2,5,3,1);X9=(5,2,4,1,3); X10=(5,3,1,4,2) N=6X1=(2,4,6,1,3,5);X2=(3,6,2,5,1,4);X3=(4,1,5,2,6,3);X4=(5,3,1, 6,4,2)N=7 40个解 N=8 92个解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;2 / 6return 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;}3 / 6实验结果截图:5. 流程图4 / 6D.心得体会通过算法老师布置的这次大作业,首先使我们更好地理解皇后问题和回溯法的原理;其次,在作业过程中遇到的困难,使我们3人学会了如何合作才能更高效的解决问题;最后,在这次作业中,锻炼了我们收集资料,学习新技能的能力,感谢老师~E.参考文献《算法设计技巧与分析》——电子工业出版社《C程序设计》——西安电子科技大学出版社《回溯法》——百度文库5 / 6。

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>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; }三.实验的结果及分析……………四.实验心得体会通过这次实验理解了回溯法的基本思想:确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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 6
2. c[k]=0 //没有放皇后
3. end for
4. flag=false
5. k=1
6. while k>=1
7.while c[k]<=5
8.c[k]=c[k]+1
9.if c为合法着色 then set flag=ture 且从两个while循环退出
10.else if c是部分解 then k=k+1
11.end while
12. c[k]=0 //回溯并c[k]=0
13. k=k-1
14. end while
15. if flag then output c
16. 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++; //方案数加1
if(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<<" 种放置方法。

"<<endl;
cout<<endl;
return;
}
else queen[i]++; //前一行皇后右移一列
}
}
}
void main()
{
while(1)
{
clock_t start, finish;
double duration;
int N;
cout<<"请输入皇后个数:"<<endl;
cin>>N;
int* queen=new int[N];
for (int i=0;i<N;i++) queen[i] = 0; //八皇后全放在第0列
int n=N; /* 定义数组p[N]用来存放结果序列,n为行号 */
start=clock();
total=0;
backtrace(queen,N);
finish=clock();
duration=(double)(finish-start);
cout<<"为找出放置方法系统共耗时 "<<duration/1000<<" 秒!\n"<<endl;
delete []queen;
}
}
运行结果:
回溯法求解八皇后问题
2010-10-29 18:28:56| 分类:算法分析 | 标签:皇后回溯数组位置八皇后问题|举报|字号订阅
问题描述:八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

问题历史:八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔于1848年提出。

之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。

八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。

诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。

1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。

转化规则:其实八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。

当且仅当n = 1 或n ≥ 4 时问题有解。

令一个一位数组a[n]保存所得解,其中a[i] 表示把第i个皇后放在第i行的列数(注意i的值都是从0开始计算的),下面就八皇后问题做一个简单的从规则到问题提取过程。

(1)因为所有的皇后都不能放在同一列,因此数组的不能存在相同的两个值。

(2)所有的皇后都不能在对角线上,那么该如何检测两个皇后是否在同一个对角线上?我们将棋盘的方格成一个二维数组,如下:
假设有两个皇后被放置在(i,j)和(k,l)的位置上,明显,当且仅当
|i-k|=|j-l|时,两个皇后才在同一条对角线上。

算法原型:上面我们搞清楚了在解决八皇后问题之前需要处理的两个规则,并将规则转化到了我们数学模型上的问题,那么这段我们开始着手讨论如何设计
明显,回溯的思想是:假设某一行为当前状态,不断检查该行所有的位置是否能放一个皇后,检索的状态有两种:
(1)先从首位开始检查,如果不能放置,接着检查该行第二个位置,依次检查下去,直到在该行找到一个可以放置一个皇后的地方,然后保存当前状态,转到下一行重复上述方法的检索。

(2)如果检查了该行所有的位置均不能放置一个皇后,说明上一行皇后放置的位置无法让所有的皇后找到自己合适的位置,因此就要回溯到上一行,重新检查该皇后位置后面的位置。

是否注意到?如果我们用一个数组来保存当前的状态,上面的检索过程是否有点像堆栈的操作?如果找到可行位置,压栈,如果当前行所有位置不行,将出栈。

好了,问题模型逐渐清晰开来了,我们可以定义一个过程,这个过程负责检索的过程,如果检索到当前行某个位置可行,压栈,如果当前行所有位置不行,将执行出栈操作。

8皇后问题,我们假定栈的大小为8,如果栈满了,表示找到了可行方法,将执行所有出栈操作。

也许有同学会问:如果我找到了一个方法,在进入找下一个可行方法时,该如何做到找出的方法不重复?我们是否需要为每行设定一个状态变量?其实这个问题的处理方法很简单:其实我们在回溯的时候,每个皇后所在位置就是该行的状态变量,回溯转到下一个位置的时候,只需后移1位即可,也就是i++。

OK,其实我们可以使用一个数组来模拟栈的结构就可以了,上面解说的时候不用数组而使用栈是因为栈的结构比数组更形象而已。

根据上述想法,我们必须定义一个过程,这个过程用来检查当前行的某个位置是否可行,为了方便大家阅读,我采用了常用的算法描述语言SPARKS 。

SPARKS 有个最大的特点就是非常注重算法的思想而不是代码,这样可以更加清晰明了地帮助读者了解作者的算法思想。

(2)利用上述的检索过程,通过递归的方式,来确定每个皇后的位置———回。

相关文档
最新文档