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皇后问题#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皇后问题

算法设计与分析实验报告姓名:杨勇涛班级:计科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皇后问题的解法,并对不同的算法进行性能分析。
实验方法:本实验采用Python语言编写程序,实现了两种常见的解法:回溯法和遗传算法。
回溯法是一种穷举搜索的方法,通过不断尝试每一种可能的放置方式,直到找到满足条件的解;而遗传算法则是通过模拟生物进化的过程,利用选择、交叉和变异等操作逐步优化解的质量。
实验结果:在实验中,我们分别测试了回溯法和遗传算法在不同规模的n皇后问题上的性能表现。
以下是实验结果的总结:1. 回溯法:- 对于规模较小的问题(n<10),回溯法可以在短时间内找到所有解,并输出结果。
- 随着问题规模的增大,回溯法的搜索时间呈指数级增长。
当n=15时,搜索时间已经超过10秒。
- 回溯法在解决大规模问题时,遇到了组合爆炸的问题,无法在合理的时间内得出结果。
2. 遗传算法:- 遗传算法对于规模较小的问题表现不如回溯法,因为其需要较长的时间来找到一个较优解。
- 随着问题规模的增大,遗传算法的性能逐渐超过回溯法。
当n=20时,遗传算法能够在合理的时间内找到一个较优解。
- 遗传算法在解决大规模问题时,相比回溯法有明显的优势,因为其搜索时间增长较慢。
实验讨论:通过对实验结果的分析,我们可以得出以下结论:- 回溯法适用于规模较小的n皇后问题,但在大规模问题上的性能不佳。
- 遗传算法在大规模问题上表现较好,但对于规模较小的问题需要更长的时间来找到较优解。
- 遗传算法的性能受到参数设置的影响,不同的选择、交叉和变异策略可能导致不同的结果。
结论:综上所述,回溯法和遗传算法都是解决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皇后问题实验报告【实验题目】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皇后问题实验步骤

湖州师范学院实验报告课程名称:算法实验四:回溯算法一、实验目的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后问题算法一、实验目的及要求所要涉及或掌握的知识: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<<" 种放置方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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)利用上述的检索过程,通过递归的方式,来确定每个皇后的位置———回。