实验报告:回溯法求解N皇后问题(Java实现)
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皇后问题java实现
N皇后问题java实现N皇后问题是⼀个典型的约束求解问题,利⽤递归机制,可以很快的得到结果。
N皇后问题的描述:在⼀个n*n的棋盘上,摆放n个皇后,要求每个皇后所在⾏、列、以及两个对⾓线上不能出现其他的皇后,否则这些皇后之间将会相互攻击。
如下图所⽰。
利⽤递归机制,可以很容易的求解n皇后问题。
针对⼋皇后,总共有92种解。
下⾯将给出N-皇后问题的⼀般求解代码,在这⾥代码是使⽤java编码的。
总共设计了三个类,⼀个是皇后类(Queen),⼀个棋盘类(Board),⼀个是求解主程序类(NQueens)。
具体代码如下:1: import java.util.ArrayList;2: import java.util.List;3:4: public class NQueens {5:6: private int numSolutions;//求解结果数量7: private int queenSize;//皇后的多少8: private Board board;//棋盘9: private List<Queen> queens = new ArrayList<Queen>();//皇后10: //private List<Queen> nQueens = new ArrayList<Queen>();11:12: public NQueens(){13:14: }15:16: public NQueens(int size){17: numSolutions = 0;18: queenSize = size;19: board = new Board(queenSize);20: for (int i = 0; i < queenSize; i++) {21: Queen queen = new Queen();22: queens.add(queen);23: }24:25: }26:27: public void solve(){28: System.out.println("Start solve....");29: putQueen(0);30: }31:32: private void putQueen(int index){33:34: int row = index;35: //如果此列可⽤36: for (int col = 0; col < board.getQueenSize(); col++) {37: if (board.getLayout()[row][col] == 0) {38: //将皇后的位置置为此列位置39: queens.get(row).setPosition(col);40: //然后将相应的位置(此列的正下⽅以及两个对⾓线)加1(即使其不可⽤) 41: for (int i = row + 1; i < board.getQueenSize(); i++) {42: board.getLayout()[i][col] ++;43: if (row + col - i >= 0) {44: board.getLayout()[i][row + col - i] ++;45: }46: if (i + col - row < board.getQueenSize()) {47: board.getLayout()[i][i + col - row] ++;48: }49: }50:51: if (row == board.getQueenSize()-1) {52: numSolutions++;53: printSolution(numSolutions);54: }else {55: putQueen(row + 1);56: }57: //回溯,将相应的位置(此列的正下⽅以及两个对⾓线)减158: for (int i = row + 1; i < board.getQueenSize(); i++) {59: board.getLayout()[i][col] --;60: if (row + col - i >= 0) {61: board.getLayout()[i][row + col - i] --;62: }63: if (i + col - row < board.getQueenSize()) {64: board.getLayout()[i][i + col - row] --;65: }66: }67:68: }69: }70: }71: //打印求解结果72: private void printSolution(int i){73: System.out.println("The "+i+ " solution is:");74: for (int j = 0; j < board.getQueenSize(); j++) {75: for (int k = 0; k < board.getQueenSize(); k++) {76: System.out.print(queens.get(j).getPosition() == k ? " * ":" - ");77: }78: System.out.println();79: }80: System.out.println();81: }82: /**83: * @param args84: */85: public static void main(String[] args) {86: //可以改变参数87: NQueens nQueens = new NQueens(8);88: nQueens.solve();89:90: }91:92:93:94: }95: import java.io.Serializable;96:97: //皇后类98: public class Queen implements Serializable, Cloneable {99:100: /**101: *102: */103: private static final long serialVersionUID = 7354459222300557644L; 104: //皇后的位置105: private int position;106:107: public Queen(){108:109: }110:111: public int getPosition() {112: return position;113: }114:115: public void setPosition(int position) {116: this.position = position;117: }118:119: public Object clone() throws CloneNotSupportedException {120:121: return super.clone();122: }123: }124:125: import java.io.Serializable;126:127: //棋盘类128: public class Board implements Serializable,Cloneable {129:130: /**131: *132: */133: private static final long serialVersionUID = -2530321259544461828L; 134:135: //棋盘的⼤⼩136: private int queenSize;137:138: //棋盘的布局139: private int[][] layout;140:141: public Board(int size){142: this.queenSize = size;143: yout = new int[queenSize][queenSize];144: //初始化,使棋盘所有位置都可⽤,即全部置为0145: for (int i = 0; i < queenSize; i++) {146: for (int j = 0; j < queenSize; j++) {147: layout[i][j] = 0;148:149: }150: }151: }152:153: public int getQueenSize() {154: return queenSize;155: }156:157: public void setQueenSize(int queenSize) {158: this.queenSize = queenSize;159: }160:161: public int[][] getLayout() {162: return layout;163: }164:165: public void setLayout(int[][] layout) {166: yout = layout;167: }168:169: public Object clone() throws CloneNotSupportedException { 170:171: return super.clone();172: }173:174: }175:。
回溯法实验(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; //返回不同解的个数}。
回溯法解皇后问题
Ch1-绪论1. 回溯法解皇后问题#include "stdio.h"#include "math.h"#include "stdlib.h"void queen(int n){ int i,j,k,jt,*q;q=malloc(n*sizeof(int));for(i=0; i<n; i++) q[i]=0;i=0; jt=1;printf("\n");printf("%d queen problem\n",n);while(jt==1){ if (q[i]<n){ k=0;while((k<i)&&((q[k]-q[i])*(fabs(q[k]-q[i])-fabs(k-i)))!=0) k=k+1;if (k<i) q[i]=q[i]+1;else{ if (i==n-1){ for(j=0; j<n; j++)printf("%5d",q[j]+1);printf("\n");q[n-1]=q[n-1]+1;}else i=i+1;}}else{ q[i]=0; i=i-1;if (i<0){ printf("\n"); free(q); return; }q[i]=q[i]+1;}}}2. 简单二分法求方程实根(1)#include "stdio.h"#include "math.h"double root(a,b,eps,f)double a,b,eps,(*f)();{ double f0,f1,c;f0=(*f)(a);while (fabs(a-b)>=eps){ c=(a+b)/2; f1=(*f)(c);if (f1==0) return(c);if (f0*f1>0) a=c;else b=c;}c=(a+b)/2;return(c);}(2)#include "root.c"main(){ double a,b,eps,f();a=1; b=2; eps=0.000001;printf("x=%7.3f\n",root(a,b,eps,f));}double f(x)double x;{ double y;y=x+log(x)-2.2;return(y);}Ch2-矩阵与线性代数方程组(1)文件头:#include "math.h"#include "stdio.h"int maqr(m,n,a,q)int m,n;double a[],q[];{ int i,j,k,l,nn,p,jj;double u,alpha,w,t;if (m<n){ printf("fail\n"); return(0);}for (i=0; i<=m-1; i++)for (j=0; j<=m-1; j++){ l=i*m+j; q[l]=0.0;if (i==j) q[l]=1.0;}nn=n;if (m==n) nn=m-1;for (k=0; k<=nn-1; k++){ u=0.0; l=k*n+k;for (i=k; i<=m-1; i++){ w=fabs(a[i*n+k]);if (w>u) u=w;}alpha=0.0;for (i=k; i<=m-1; i++){ t=a[i*n+k]/u; alpha=alpha+t*t;}if (a[l]>0.0) u=-u;alpha=u*sqrt(alpha);if (fabs(alpha)+1.0==1.0){ printf("fail\n"); return(0);}u=sqrt(2.0*alpha*(alpha-a[l]));if ((u+1.0)!=1.0){ a[l]=(a[l]-alpha)/u;for (i=k+1; i<=m-1; i++){ p=i*n+k; a[p]=a[p]/u;}for (j=0; j<=m-1; j++){ t=0.0;文件尾:for (jj=k; jj<=m-1; jj++)t=t+a[jj*n+k]*q[jj*m+j];for (i=k; i<=m-1; i++){ p=i*m+j; q[p]=q[p]-2.0*t*a[i*n+k];}}for (j=k+1; j<=n-1; j++){ t=0.0;for (jj=k; jj<=m-1; jj++)t=t+a[jj*n+k]*a[jj*n+j];for (i=k; i<=m-1; i++){ p=i*n+j; a[p]=a[p]-2.0*t*a[i*n+k];}}a[l]=alpha;for (i=k+1; i<=m-1; i++)a[i*n+k]=0.0;}}for (i=0; i<=m-2; i++)for (j=i+1; j<=m-1;j++){ p=i*m+j; l=j*m+i;t=q[p]; q[p]=q[l]; q[l]=t;}return(1);}(2)#include "stdio.h"#include "maqr.c"main(){ int i,j;static double q[4][4],a[4][3]={ {1.0,1.0,-1.0}, {2.0,1.0,0.0},{1.0,-1.0,0.0},{-1.0,2.0,1.0}};i=maqr(4,3,a,q);if (i!=0){ printf("MAT Q IS:\n");for (i=0; i<=3; i++){ for (j=0; j<=3; j++)printf("%13.7e ",q[i][j]);printf("\n");}printf("\n");printf("MAT R IS:\n");for (i=0; i<=3; i++){ for (j=0; j<=2; j++)printf("%13.7e ",a[i][j]);printf("\n");}printf("\n");}}(3)文件头:#include "stdlib.h"#include "math.h"int muav(m,n,a,u,v,eps,ka)int m,n,ka;double eps,a[],u[],v[];{ int i,j,k,l,it,ll,kk,ix,iy,mm,nn,iz,m1,ks;double d,dd,t,sm,sm1,em1,sk,ek,b,c,shh,fg[2],cs[2]; double *s,*e,*w;void ppp();void sss();s=malloc(ka*sizeof(double));e=malloc(ka*sizeof(double));w=malloc(ka*sizeof(double));it=60; k=n;if (m-1<n) k=m-1;l=m;if (n-2<m) l=n-2;if (l<0) l=0;ll=k;if (l>k) ll=l;if (ll>=1){ for (kk=1; kk<=ll; kk++){ if (kk<=k){ d=0.0;for (i=kk; i<=m; i++){ ix=(i-1)*n+kk-1; d=d+a[ix]*a[ix];}s[kk-1]=sqrt(d);if (s[kk-1]!=0.0){ ix=(kk-1)*n+kk-1;if (a[ix]!=0.0){ s[kk-1]=fabs(s[kk-1]);if (a[ix]<0.0) s[kk-1]=-s[kk-1];}for (i=文件尾:{ int i,j,p,q;double d;if (m>=n) i=n;else i=m;for (j=1; j<=i-1; j++){ a[(j-1)*n+j-1]=s[j-1];a[(j-1)*n+j]=e[j-1];}a[(i-1)*n+i-1]=s[i-1];if (m<n) a[(i-1)*n+i]=e[i-1];for (i=1; i<=n-1; i++)for (j=i+1; j<=n; j++){ p=(i-1)*n+j-1; q=(j-1)*n+i-1;d=v[p]; v[p]=v[q]; v[q]=d;}return;}static void sss(fg,cs)double cs[2],fg[2];{ double r,d;if ((fabs(fg[0])+fabs(fg[1]))==0.0){ cs[0]=1.0; cs[1]=0.0; d=0.0;} else{ d=sqrt(fg[0]*fg[0]+fg[1]*fg[1]);if (fabs(fg[0])>fabs(fg[1])){ d=fabs(d);if (fg[0]<0.0) d=-d;}if (fabs(fg[1])>=fabs(fg[0])){ d=fabs(d);if (fg[1]<0.0) d=-d;}cs[0]=fg[0]/d; cs[1]=fg[1]/d;}r=1.0;if (fabs(fg[0])>fabs(fg[1])) r=cs[1];elseif (cs[0]!=0.0) r=1.0/cs[0];fg[0]=d; fg[1]=r;return;}#include "stdio.h"#include "cgauss.c"main(){ int i;static double ar[4][4]={ {1.0,3.0,2.0,13.0},{7.0,2.0,1.0,-2.0},{9.0,15.0,3.0,-2.0},{-2.0,-2.0,11.0,5.0}};static double ai[4][4]={ {3.0,-2.0,1.0,6.0},{-2.0,7.0,5.0,8.0},{9.0,-3.0,15.0,1.0},{-2.0,-2.0,7.0,6.0}}; static double br[4]={2.0,7.0,3.0,9.0};static double bi[4]={1.0,2.0,-2.0,3.0};if (cgauss(4,ar,ai,br,bi)!=0)for (i=0;i<=3;i++)printf("b(%d)=%13.7e +j %13.7e\n",i,br[i],bi[i]); }。
回溯法解决N后问题
实验名称
随机与回溯结合解决八皇后问题
课程名称
算法分析与设计
姓名
***
专业班级学号
计算机08-1班
20080701****
日期
2011.06.15
地点
西一楼207
成绩
教师
***,***
一、
1.掌握回溯法的设计思想。
2.设计回溯算法完成N后问题求解。
3.考察回溯法求解问题的有效程度。
二、
}
}
}
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.Backtrack(1);
delete []p;
return X.sum;
}
for(j=1;j<=8;j++) /*第i)/*即相应的三个数组的对应元素值为1*/
{占用位置(i,j)/*置相应的三个数组对应的元素值为0*/
if i<8
为i+1个皇后选择合适的位置;
else输出一个解
}
四、
皇后个数为1:
皇后个数为2:
皇后个数为3:
皇后个数为4:
皇后个数为8时:
五、
本实验是在别人代码的基础上,结合自己对回溯算法的理解改的。在最初的时候,遇到了很大的麻烦,毕竟是改的别人的代码,对代码的理解不是很透彻,出现了很多错误,但在同学们的帮助下,通过自己的一个下午加一个晚上的修改,终于调试成功。
N皇后问题——JAVA实现(源代码)
2011/2012学年第2学期“算法分析与设计”上机报告目录1. 问题描述 (3)2. 算法分析 (3)3. 伪代码 (4)4. 演示程序设计 (5)5. 演示界面 (5)6. 算法实现 (8)7. 总结 (19)8. 参考文献 (20)1.问题描述:N皇后问题(n-queen problem)是一个经典的组合优化问题,也是一个使用回溯法(backtracking)的典型例子。
回溯法是一种系统地搜索问题解的方法。
为了实现回溯,首先需要为为问题定义一个解空间(solution space),其至少包含问题的一个解(可能是最优解)。
我们要从中找出满足问题约束条件的解,即可行解(feasible solution)。
回溯算法一次扩展一个解,在对部分解进行扩展后,检查到目前为止的解是否为问题的一个解,如果是,则输出;否则,检查是否可以继续扩展。
如果可以,则继续扩展;否则,删除最后添加的元素,尝试当前位置是否有另一元素。
若没有合法的扩展方式,则进行回溯(backtrack)。
N皇后问题要求在一个n×n的棋盘上放置n个皇后,且使得每两个皇后之间都不能相互攻击,即它们中的任意两个都不能位于同一行、同一列或者同一对角线上。
这次的任务就是借助GUI实现N皇后问题的动态演示。
我们设定皇后个数在四个到八个之间可选,所选编程语言为JA V A。
2.算法分析:N皇后问题是回溯法的一个经典例子,它的要求就是要找出在n×n的棋盘上放置n个皇后并使其不能相互攻击的所有解。
设X=(x1,x2,…,xn)表示问题的解,,其中xi表示第i皇后放在第i行所在的列数。
由于不存在两个皇后位于同一列上,因此xi互不相同。
设有两个皇后分别位于棋盘( i , j )和( k , l )处,如果两个皇后位于同一对角线上,则表明它们所在的位置应该满足:i – j = k – l或i + j = k + l。
综合这两个等式可得,如果两个皇后位于同一对角线上,那么它们的位置关系一定满足| j – l | = | i – k |。
n皇后 实验报告
n皇后实验报告n皇后实验报告引言:n皇后问题是一个经典的数学问题,其目标是在一个n×n的棋盘上放置n个皇后,使得它们互不攻击。
本实验旨在通过编程实现n皇后问题的解法,并对不同的算法进行性能分析。
实验方法:本实验采用Python语言编写程序,实现了两种常见的解法:回溯法和遗传算法。
回溯法是一种穷举搜索的方法,通过不断尝试每一种可能的放置方式,直到找到满足条件的解;而遗传算法则是通过模拟生物进化的过程,利用选择、交叉和变异等操作逐步优化解的质量。
实验结果:在实验中,我们分别测试了回溯法和遗传算法在不同规模的n皇后问题上的性能表现。
以下是实验结果的总结:1. 回溯法:- 对于规模较小的问题(n<10),回溯法可以在短时间内找到所有解,并输出结果。
- 随着问题规模的增大,回溯法的搜索时间呈指数级增长。
当n=15时,搜索时间已经超过10秒。
- 回溯法在解决大规模问题时,遇到了组合爆炸的问题,无法在合理的时间内得出结果。
2. 遗传算法:- 遗传算法对于规模较小的问题表现不如回溯法,因为其需要较长的时间来找到一个较优解。
- 随着问题规模的增大,遗传算法的性能逐渐超过回溯法。
当n=20时,遗传算法能够在合理的时间内找到一个较优解。
- 遗传算法在解决大规模问题时,相比回溯法有明显的优势,因为其搜索时间增长较慢。
实验讨论:通过对实验结果的分析,我们可以得出以下结论:- 回溯法适用于规模较小的n皇后问题,但在大规模问题上的性能不佳。
- 遗传算法在大规模问题上表现较好,但对于规模较小的问题需要更长的时间来找到较优解。
- 遗传算法的性能受到参数设置的影响,不同的选择、交叉和变异策略可能导致不同的结果。
结论:综上所述,回溯法和遗传算法都是解决n皇后问题的有效方法,但在不同规模的问题上有不同的性能表现。
在实际应用中,我们可以根据问题规模选择合适的算法来求解。
对于规模较小的问题,回溯法可以提供精确的解;而对于大规模问题,遗传算法能够在合理的时间内找到较优解。
回溯法求N皇后问题
Tree-回溯法求N皇后问题#include <stdio.h>#include <malloc.h>#define N 4 //N皇后typedef int Chessboard[N + 1][N + 1]; //第0号位置不用bool check(Chessboard cb, int i, int j) { //看棋盘cb是否满足合法布局int h, k;int m = i + j, n = i - j;for(h=1; h<i; h++) {if(cb[h][j] == 1 && h != i) return false; //检查第j列if(m-h<=N && cb[h][m-h] == 1 && h != i) return false; //检查斜的,m-h<=N是为了保证不越界if(h-n<=N && cb[h][h-n] == 1 && h != i) return false; //检查斜的,h-n<=N是为了保证不越界}for(k=1; k<N; k++)/*检查第i行的*/ if(cb[i][k] == 1 && k != j) return false;return true;}void printfChessboard(Chessboard cb) {//打印棋盘int i, j;for(i=1; i<=N; i++) {for(j=1; j<=N; j++) printf("%d ", cb[i][j]);printf("\n");}printf("\n");}/*进入本函数时,在n*n棋盘前n-1行已放置了互不攻击的i-1个棋子。
现从第i行起继续为后续棋子选择合适位置。
回溯法求解N皇后问题
2.用适于搜索的方式组织该空间。
3.用深度优先法搜索该空间,利用界限函数避免移动到不可能产生解的子空间。
二.实验内容
问题描述:
在n×n格的棋盘上放置彼此不受攻击的n个皇后,按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子,求解可以放置的方法种数。
1.编程实现n皇后算法。
2.用图形输出中间过程。
3.在程序中添加统计扩展节点数,估计算法的复杂性。
三.问题分析
n后问题等于于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。即规定每一列放一个皇后,不会造成列上的冲突;当第i行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以i为下标的标记置为被占领状态。
华北电力大学科技学院
实验ቤተ መጻሕፍቲ ባይዱ告
|
|
实验名称回溯法求解N皇后问题
课程名称算法设计与分析
|
|
专业班级:学生姓名:
学号:成绩:
指导教师:实验日期:
一.实验目的及要求:
掌握回溯法基本思想及解题步骤。
回溯法的求解过程实质上是一个优先遍历一棵树状的过程,只是这棵树不是遍历前预先建立的,而是隐含在遍历过程中的。
回溯法的步骤:
System.exit(-1);
}return string;
}
//
//
}
//N皇后计算
class Nqueens
{
int n;
public Nqueens(int n)
{
this.n=n;
}
int x[];
int sum=0;
public boolean Place(int k)
用回溯算法解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皇后问题(Java实现)
实验报告一、实验名称:回溯法求解N皇后问题(Java实现)二、学习知识:回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并以此慢慢地扩大问题规模,迭代地逼近最终问题的解。
这种迭代类似于穷举并且是试探性的,因为当目前的可能答案被测试出不可能可以获得最终解时,则撤销当前的这一步求解过程,回溯到上一步寻找其他求解路径。
为了能够撤销当前的求解过程,必须保存上一步以来的求解路径,这一点相当重要。
三、问题描述N皇后问题:在一个 N * N 的国际象棋棋盘中,怎样放置 N 个皇后才能使N 个皇后之间不会互相有威胁而共同存在于棋局中,即在 N * N 个格子的棋盘中没有任何两个皇后是在同一行、同一列、同一斜线上。
深度优先遍历的典型案例。
四、求解思路1、求解思路:最容易想到的方法就是有序地从第1列的第 1 行开始,尝试放上一个皇后,然后再尝试第2 列的第几行能够放上一个皇后,如果第 2 列也放置成功,那么就继续放置第 3 列,如果此时第3列没有一行可以放置一个皇后,说明目前为止的尝试是无效的(即不可能得到最终解),那么此时就应该回溯到上一步(即第 2 步),将上一步(第 2 步)所放置的皇后的位置再重新取走放在另一个符合要求的地方…如此尝试性地遍历加上回溯,就可以慢慢地逼近最终解了。
2、需要解决的问题:如何表示一个N * N 方格棋盘能够更有效?怎样测试当前所走的试探路径是否符合要求?这两个问题都需要考虑到使用怎样的数据结构,使用恰当的数据结构有利于简化编程求解问题的难度。
3、我们使用以下的数据结构:int column[col] = row 表示第 col 列的第 row 行放置一个皇后boolean rowExi sts[i] = true 表示第 i 行有皇后boolean a[i] = true 表示右高左低的第 i 条斜线有皇后(按→↓顺序从1~ 2*N -1 依次编号)boolean b[i] = true 表示左高右低的第 i 条斜线有皇后(按→↑顺序从1~ 2*N -1 依次编号)五、算法实现对应这个数据结构的算法实现如下:1.**2. * 回溯法求解N 皇后问题3. * @author haollo yin4. */5.public classN_Quee ns {6.7.// 皇后的个数8. privat e int queens Num = 4;9.10.// column[i] = j表示第 i 列的第 j 行放置一个皇后11. privat e int[] queens = new int[queens Num + 1];12.13.// rowExi sts[i] = true 表示第 i 行有皇后14. privat e boolea n[] rowExi sts = new boolea n[queensNum + 1];15.16.// a[i] = true 表示右高左低的第 i 条斜线有皇后17. privat e boolea n[] a = new boolea n[queens Num * 2];18.19.// b[i] = true 表示左高右低的第 i 条斜线有皇后20. privat e boolea n[] b = new boolea n[queens Num * 2];21.22.// 初始化变量23. privat e void init() {24. for (int i = 0; i < queens Num + 1; i++) {25. rowExi sts[i] = false;26. }27.28. for(int i = 0; i < queens Num * 2; i++) {29. a[i] = b[i] = false;30. }31. }32.33.// 判断该位置是否已经存在一个皇后,存在则返回true34. privat e boolea n isExis ts(int row, int col) {35. return (rowExi sts[row] || a[row + col - 1]|| b[queens Num + col - row]);36. }37.38.// 主方法:测试放置皇后39. public void testin g(int column) {40.41.// 遍历每一行42. for (int row = 1; row < queens Num + 1; row++) {43.// 如果第 row 行第 column列可以放置皇后44. if (!isExis ts(row, column)) {45.// 设置第 row 行第 column列有皇后46. queens[column] = row;47.// 设置以第 row 行第 column列为交叉点的斜线不可放置皇后48. rowExi sts[row] = a[row + column - 1] = b[queens Num + column - row] = true;49.50.// 全部尝试过,打印51. if(column == queens Num) {52. for(int col = 1; col <= queens Num; col++) {53. System.out.print("("+col +"," + queens[col] + ") ");54. }55. System.out.printl n();56. }else {57.// 放置下一列的皇后58. testin g(column + 1);59. }60.// 撤销上一步所放置的皇后,即回溯61. rowExi sts[row] = a[row + column - 1] = b[queens Num + column - row] = false;62. }63. }64. }65.66.//测试67. public static void main(String[] args) {68. N_Quee ns queen= new N_Quee ns();69. queen.init();70.// 从第 1 列开始求解71. queen.testin 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皇后问题,并对它们的效率和性能进行评估。
实验一:暴力法暴力法是最简单直接的解决方法之一。
它通过穷举法遍历所有可能的皇后放置方式,并检查是否满足条件。
具体步骤如下: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皇后问题
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皇后问题实验报告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后问题课程名称: 算法分析与设计姓名: 李少卿专业班级: 计算机科学与技术08-1班学号: 200807010119日期: 2011.06.01 地点: 西一楼207成绩: 地点: 苏晓珂、李灿林1.实验目的结合随机算法和回溯求解N皇后问题,使得在NxN格的国际象棋上摆放N个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
2.实验内容(1) 算法分析N皇后问题一般是采用回溯法求解,但当N值较大时,回溯算法效率较低,所以此次作业中将随机算法和回溯法结合起来求解N皇后问题,以提高算法的效率。
引入随机算法,能保证每次找出的解是正确的,但可能在一次求解过程中找不出可行解,这一点在程序运行过程中能得到体现。
所以解决N皇后问题所采取的方法是先用随机函数产生一部分的解(这一部分可以占全部的三分之一),再用回溯法将其余的结果计算出来。
(2) 源代码#include <iostream>#include <cmath>#include <time.h>using namespace std;int count,rand_count;//判断第k个皇后的位置是否满足要求 bool place(int x[],int k) {int i;for (i = 1;i<k;++i){( (x[i]==x[k])||( abs(x[i]-x[k])==abs(i-k) ) ) if{return false;}}return true;}//回溯法+随机法求解n皇后问题 void Rand_Back_n_queens(int n,int x[]) {int k,mid;mid = n/3;time_t t;srand((unsigned) time(&t));printf("\n随机产生的值:\n");for (k = 1;k<=mid;++k){x[k] = rand()%n + 1;while (!place(x,k)){x[k] = rand()%n + 1;}printf("%d\t",x[k]);}k = mid+1;x[k] = 0;while (k>mid){++x[k];while ( (x[k]<=n)&&(!place(x,k)) ) {++x[k];}if (x[k]<=n){if (k==n)break;else{++k;x[k] = 0;}}else{x[k] = 0;--k;}}printf("\n回溯法产生的值:\n");for (int i = mid+1; i<=n; ++i)printf("%d\t",x[i]); }int main(){int n;printf("回溯法+随机法求解n皇后问题,请输入n值(输入0则退出): "); while (scanf("%d",&n),0!=n){int *x = new int[n+1];Rand_Back_n_queens(n,x);delete []x;x = NULL;printf("\n\n请输入n值(输入0则退出): ");}return 0;}(3) 实验结果输入代码后编译并调试程序。
JAVA实现N皇后问题(回溯法)
int sum = 0;//当前已找到的可行方案数 public int totalNQueens(int n) { N = n; x = new int[N+1]; backTrace(1); return sum; } /** * col行这个点,x[col]列这个点。与已经存在的几个皇后。是否符合要求,放到这个位置上, * @param col * @return */ private boolean place(int col){ for(int i = 1; i < col; i++){
网络错误503请刷新页面重试持续报错请尝kage com.leetCode; /** * Follow up for N-Queens problem. Now, instead outputting board configurations, return the total number of distinct solutions. * @author Zealot * @date 2015年7月23日 下午6:14:49 */ public class NQueensII { int[] x;//当前解 int N;//皇后个数
if(Math.abs(col - i)==Math.abs(x[col]-x[i])||x[col]==x[i]){ return false; } } return true; } private void backTrace(int t) { if(t>N){ sum++; }else { //第t行。遍历全部的节点 for(int j = 1; j <= N; j++) { x[t] = j ; //假设第j个节点能够放下皇后 if(place(t)){ //接着放下一个 backTrace(t+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行的皇后有冲突
回溯算法解决N皇后问题实验及其代码
回溯算法解决N皇后问题实验及其代码(共2页)--本页仅作为文档封面,使用时请直接删除即可----内页可以根据需求调整合适字体及大小--实验报告4 回溯算法实验4 回溯算法解决N皇后问题一、实验目的1)掌握回溯算法的实现原理,生成树的建立以及限界函数的实现;2)利用回溯算法解决N皇后问题;二、实验内容回溯算法解决N皇后问题。
三、算法设计1)编写限界函数 bool PLACE(int k,int x[]),用以确定在k列上能否放置皇后;2)编写void NQUEENS(int n)函数用以摆放N个皇后;3)编写主函数,控制输入的皇后数目;4)改进和检验程序。
四、程序代码";}}cout<<"\n";}cout<<"\n";}else { k=k+1; x[k]=0;} //移向下一行}else k=k-1; //回溯}}bool PLACE(int k,int x[]){/* 如果一个皇后能放在第k行和x(k)列,返回ture;否则返回false。
x是一个全局变量,进入此过程的时候已经置了k个值。
ABS(r)过程返回r的绝对值*/int i=0;while (i<k){if( x[i]==x[k]||abs(x[i]-x[k])==abs(i-k) )return (false); //在同一列或者在同一斜角线上有两个皇后i=i+1;}return (true);}五、运行结果输入皇后的个数为4,程序输出如下:六、结果分析此程序用回溯算法成功地解决了N皇后问题,以上输入的值为:4,由结果的显示可知,程序切实可行。
通过输入其它数值并分析可知:随着皇后数目的增大,排列的个数也越多!。
n皇后实验报告
n皇后实验报告实验报告实验名称 n皇后问题课程名称计算机算法设计与分析专业班级:学生姓名:学号:成绩:指导老师:实验日期:a)x[i]≠x[j] ,i≠j :不允许将任何两个皇后放在同一列上;b)|j-i|≠|x[j]-x[i]| :不允许两个皇后位于同一条斜线上。
问题的解空间的形式为:要找出”四皇后”问题的解,最可靠的方法就是把各种情况全部检核一遍,将符合条件A的解找出来。
但这样做,你要有相当耐心才行,这是很费时的。
采用回溯算法进行求解,在搜索的过程中,将不满足条件要求的分支树减去,可以有效的降低算法的时间复杂性。
n后问题的算法描述如下:剪枝函数:bool Ok(int t){int i;for(int i=0;i<t;i++){if(x[t]==x[i] || abs(t-i)==abs(x[t]-x[i])) return 0;}return 1;}void Backtrack(int t){if(t>=n){cout<<"第"<<sum<<"个方案:\n";for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(j==x[i])cout<<"1";elsecout<<"0";}cout<<endl;}sum++;}else{for(int i=0;i<n;i++){x[t]=i;if(Ok(t))Backtrack(t+1); }}}一、实验结果五、实验代码#include<iostream>using namespace std;int *x;//当前解int n;//皇后的个数Nint sum=1;bool Ok(int t)//检查参数所指示的这一行皇后放置方案是否满足要求{int i;for(int i=0;i<t;i++){if(x[t]==x[i] || abs(t-i)==abs(x[t]-x[i]))return 0;}return 1;}void Backtrack(int t){if(t>=n){cout<<"第"<<sum<<"个方案:\n";for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(j==x[i])cout<<"1";elsecout<<"0";}cout<<endl;}sum++;}else{for(int i=0;i<n;i++){x[t]=i;if(Ok(t))Backtrack(t+1);}}}void main(){cout<<"输入皇后个数 :";cin>>n;x=(int *)malloc(sizeof(int)*n);Backtrack(0);cout<<"一共的方案数为:"<<sum-1<<"\n";system("pause");}六、实验心得通过本次实验的学习,让我了解到了用回溯法可以搜索问题的所有解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告
一、实验名称:回溯法求解N皇后问题(Java实现)
二、学习知识:
回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并以此慢慢地扩大问题规模,迭代地逼近最终问题的解。
这种迭代类似于穷举并且是试探性的,因为当目前的可能答案被测试出不可能可以获得最终解时,则撤销当前的这一步求解过程,回溯到上一步寻找其他求解路径。
为了能够撤销当前的求解过程,必须保存上一步以来的求解路径,这一点相当重要。
三、问题描述
N皇后问题:在一个 N * N 的国际象棋棋盘中,怎样放置 N 个皇后才能使 N 个皇后之间不会互相有威胁而共同存在于棋局中,即在 N * N 个格子的棋盘中没有任何两个皇后是在同一行、同一列、同一斜线上。
深度优先遍历的典型案例。
四、求解思路
1、求解思路:最容易想到的方法就是有序地从第 1 列的第 1 行开始,尝试放上一个皇后,然后再尝试第 2 列的第几行能够放上一个皇后,如果第 2 列也放置成功,那么就继续放置第 3 列,如果此时第 3 列没有一行可以放置一个皇后,说明目前为止的尝试是无效的(即不可能得到最终解),那么此时就应该回溯到上一步(即第 2 步),将上一步(第 2 步)所放置的皇后的位置再重新取走放在另一个符合要求的地方…如此尝试性地遍历加上回溯,就可以慢慢地逼近最终解了。
2、需要解决的问题:如何表示一个 N * N 方格棋盘能够更有效?怎样测试当前所走的试探路径是否符合要求?这两个问题都需要考虑到使用怎样的数据结构,使用恰当的数据结构有利于简化编程求解问题的难度。
3、我们使用以下的数据结构:
int column[col] = row 表示第 col 列的第row 行放置一个皇后
boolean rowExists[i] = true 表示第 i 行有皇后
boolean a[i] = true 表示右高左低的第 i 条斜线有皇后(按→↓顺序从1~ 2*N -1 依次编号)
boolean b[i] = true 表示左高右低的第 i 条斜线有皇后(按→↑顺序从1~ 2*N -1 依次编号)
五、算法实现
对应这个数据结构的算法实现如下:
1.**
2. * 回溯法求解 N 皇后问题
3. * @author haolloyin
4. */
5.public class N_Queens {
6.
7.// 皇后的个数
8. private int queensNum = 4;
9.
10.// column[i] = j表示第 i 列的第 j 行放置一个皇后
11. private int[] queens = new int[queensNum + 1];
12.
13.// rowExists[i] = true 表示第 i 行有皇后
14. private boolean[] rowExists = new boolean[queen
sNum + 1];
15.
16.// a[i] = true 表示右高左低的第 i 条斜线有皇后
17. private boolean[] a = new boolean[queensNum * 2
];
18.
19.// b[i] = true 表示左高右低的第 i 条斜线有皇后
20. private boolean[] b = new boolean[queensNum * 2
];
21.
22.// 初始化变量
23. private void init() {
24. for (int i = 0; i < queensNum + 1; i++) {
25. rowExists[i] = false;
26. }
27.
28. for(int i = 0; i < queensNum * 2; i++) {
29. a[i] = b[i] = false;
30. }
31. }
32.
33.// 判断该位置是否已经存在一个皇后,存在则返回 true
34. private boolean isExists(int row, int col) {
35. return (rowExists[row] || a[row + col - 1]
|| b[queensNum + col - row]);
36. }
37.
38.// 主方法:测试放置皇后
39. public void testing(int column) {
40.
41.// 遍历每一行
42. for (int row = 1; row < queensNum + 1; row+
+) {
43.// 如果第 row 行第 column 列可以放置皇后
44. if (!isExists(row, column)) {
45.// 设置第 row 行第 column 列有皇后
46. queens[column] = row;
47.// 设置以第 row 行第 column 列为交叉点
的斜线不可放置皇后
48. rowExists[row] = a[row + column - 1
] = b[queensNum + column - row] = true;
49.
50.// 全部尝试过,打印
51. if(column == queensNum) {
52. for(int col = 1; col <= queensN
um; col++) {
53. System.out.print("("+col +
"," + queens[col] + ") ");
54. }
55. System.out.println();
56. }else {
57.// 放置下一列的皇后
58. testing(column + 1);
59. }
60.// 撤销上一步所放置的皇后,即回溯
61. rowExists[row] = a[row + column - 1
] = b[queensNum + column - row] = false;
62. }
63. }
64. }
65.
66.//测试
67. public static void main(String[] args) {
68. N_Queens queen = new N_Queens();
69. queen.init();
70.// 从第 1 列开始求解
71. queen.testing(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 标志数组来表示每一条斜线的编号顺序以及方向都相当重要。
看书的时候也是费了些时间来理解的,呼…另外,queens [col] = row 数组只是用了一维而不是二维来表示纵横交错的方格棋盘上特定位置是否有皇后也是比较经济而有意思的。
2、正确运用、组织所确定的数据结构到算法的实现逻辑中也是很重要的,就像代码中的 isExists(int row, int col) 方法内的 (rowExists[row] || a[row + col - 1] || b[queensNum + col - row]) 就是很明确的理解了尝试放置皇后的位置的 x ,y 坐标与斜线之间的数值关系,才使得算法得以正确执行。
当然,对于斜线的编号、顺序也是相当重要的。