今早上看了一篇英语阅读之后,莫名有些空虚寂寞冷。拿出算法书,研读回溯法。我觉得n皇后问题完全可以用暴力方式,即先对n个数进行全排列,得到所有结果的下标组合,问题规模为n!。

全排列花了比较久的时间才编写出来。主要是没有找对思路。最终我想到了递归,即对4个数进行全排列可以化为把【对3个数进行了全排列】的结果拿出来,在下标为1-4的位置上各插上一个数,一次类推。于是我编写了全排列类:

 //全排列
class Arrangment{
int[][]ans;
Arrangment(){}
Arrangment(int[] nums){
ans=createA(nums.length,nums);
}
void printNums(int[][] nums){
int row=nums.length;
int col=nums[].length;
int i,j;
for(i=;i<row;i++){
for(j=;j<col;j++)
System.out.print(nums[i][j]+" ");
System.out.print("\n");
}
}
int[][]createA(int rank,int []nums){
int[][] re;
if(rank>){
int[][] pre=createA(rank-,nums);
int row=pre.length;
int col=nums.length;
re=new int[row*rank][rank];
int index=;
int i,j,k,m;
for(i=;i<rank;i++){
for(j=;j<row;j++){
for(k=,m=;k<rank ;k++){
if(k==i){//如果列下标等于i(在0~rank)中循环
re[index][k]=nums[rank-];
int a;
a=;
}else{
re[index][k]=pre[j][m];
m++;
}
}
index++;
}
} }
else{
re=new int[][];
re[][]=nums[];
}
return re;
}
private int factorial(int n){
int re=;
while(n>=)
re*=(n--);
return re;
}
}

使用这个全排列类,就可以构造所有的问题的求解空间了。

暴力求解算法:

 class N_Queens{
int n;
N_Queens(int inN){
n=inN;
}
List<int[]> solved =new ArrayList<int[]>();
void solveByBrutal(){//穷举求解 boolean isComplied(int[] nums,int len){
int i,j;
for(i=0;i<len-1;i++)
for(j=i+1;j<len;j++){
int a=Math.abs(i-j);
int b=Math.abs(nums[i]-nums[j]);
if(a==b || b==0)
return false;
}
return true;
}
}

然后我开始研究怎么使用【回溯法】进行解题。我看了严奶奶书上的伪代码,以及树形结构实例,感触颇深。原来我以为这个问题和8数码问题一样需要进行树的按层遍历,已经使用队列结构的,但是他既然使用了一种递归的思想,并且是深度优先的。用递归的入栈出栈,在【剪掉枝丫】(问题不可解)和【找到一个解】之后,自动的求下一个解。

回溯法代码:

 class N_Queens{
int n;
N_Queens(int inN){
n=inN;
}
List<int[]> solved =new ArrayList<int[]>();
void solveByBackTrace(){
int[] nums=null;
trial(nums,0);
}
void trial(int [] nums,int i){//棋盘上的前i行已经放置了【符合条件】的棋子
if(i<n){
int j,k;
//第i行进行放置
for(j=0;j<n;j++){//在第j列上进行遍历
int[] node=new int[n];//新建结点
for(k=0;k<i;k++)
node[k]=nums[k];//拷贝父结点
node[i]=j;//第i行第j列上放上一个皇后
if(isComplied(node,i+1)){//符合条件
trial(node,i+1);//扩展它的子节点
}
}
}else{
solved.add(nums);
}
} boolean isComplied(int[] nums,int len){
int i,j;
for(i=0;i<len-1;i++)
for(j=i+1;j<len;j++){
int a=Math.abs(i-j);
int b=Math.abs(nums[i]-nums[j]);
if(a==b || b==0)
return false;
}
return true;
}
}

完整代码:

 import java.util.*;

 public class Main {

     public static void main(String[] args) {
while(true){
System.out.print("请输入皇后的数目:");
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
N_Queens problem=new N_Queens(n);
int []nums={1,2,3};
problem.isComplied(nums, 2);
problem.solveByBrutal();
problem.PrintChecker();
}
} } //全排列
class Arrangment{
int[][]ans;
Arrangment(){}
Arrangment(int[] nums){
ans=createA(nums.length,nums);
}
void printNums(int[][] nums){
int row=nums.length;
int col=nums[0].length;
int i,j;
for(i=0;i<row;i++){
for(j=0;j<col;j++)
System.out.print(nums[i][j]+" ");
System.out.print("\n");
}
}
int[][]createA(int rank,int []nums){
int[][] re;
if(rank>1){
int[][] pre=createA(rank-1,nums);
int row=pre.length;
int col=nums.length;
re=new int[row*rank][rank];
int index=0;
int i,j,k,m;
for(i=0;i<rank;i++){
for(j=0;j<row;j++){
for(k=0,m=0;k<rank ;k++){
if(k==i){//如果列下标等于i(在0~rank)中循环
re[index][k]=nums[rank-1];
int a;
a=0;
}else{
re[index][k]=pre[j][m];
m++;
}
}
index++;
}
} }
else{
re=new int[1][1];
re[0][0]=nums[0];
}
return re;
}
private int factorial(int n){
int re=1;
while(n>=1)
re*=(n--);
return re;
}
} class N_Queens{
int n;
N_Queens(int inN){
n=inN;
}
List<int[]> solved =new ArrayList<int[]>();
void solveByBrutal(){//穷举求解
int i;
int indexs[]=new int[n];
for(i=0;i<n;i++) indexs[i]=i;
Arrangment solve=new Arrangment(indexs);
int[][] solceSpace=solve.ans;//构造所有解空间
solved.clear();
for(i=0;i<solceSpace.length;i++){
if(isComplied(solceSpace[i],n))
solved.add(solceSpace[i]);
}
int a;
a=0;
}
void solveByBackTrace(){
int[] nums=null;
trial(nums,0);
}
void trial(int [] nums,int i){//棋盘上的前i行已经放置了【符合条件】的棋子
if(i<n){
int j,k;
//第i行进行放置
for(j=0;j<n;j++){//在第j列上进行遍历
int[] node=new int[n];//新建结点
for(k=0;k<i;k++)
node[k]=nums[k];//拷贝父结点
node[i]=j;//第i行第j列上放上一个皇后
if(isComplied(node,i+1)){//符合条件
trial(node,i+1);//扩展它的子节点
}
}
}else{
solved.add(nums);
}
} boolean isComplied(int[] nums,int len){
int i,j;
for(i=0;i<len-1;i++)
for(j=i+1;j<len;j++){
int a=Math.abs(i-j);
int b=Math.abs(nums[i]-nums[j]);
if(a==b || b==0)
return false;
}
return true;
} public String toString(){
int i,j;
String str=new String("");
for(i=0;i<solved.size();i++){
int [] out=solved.get(i);
for(j=0;j<out.length;j++){
str+=out[j];
str+=" ";
}
str+="\n";
}
return str;
}
void PrintChecker(){
int i,j,k;
String out=new String();
for(i=0;i<solved.size();i++){
int[] nums=solved.get(i);
for(j=0;j<nums.length;j++){
int l=nums[j];
int r=nums.length-1-nums[j];
for(k=0;k<l;k++) out+="□";
out+="■";
for(k=0;k<r;k++) out+="□";
out+="\n";
}
out+="\n";
}
System.out.print(out);
}
}

输出结果:

4皇后:

8皇后:

10皇后:

回溯法 | n皇后问题的更多相关文章

  1. 八皇后问题-回溯法(MATLAB)

    原创文章,转载请注明:八皇后问题-回溯法(MATLAB) By Lucio.Yang 1.问题描述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后,使其不能 ...

  2. Java算法——回溯法

    回溯法一种选优搜索法,又称试探法.利用试探性的方法,在包含问题所有解的解空间树中,将可能的结果搜索一遍,从而获得满足条件的解.搜索过程采用深度遍历策略,并随时判定结点是否满足条件要求,满足要求就继续向 ...

  3. 回溯法解决N皇后问题(以四皇后为例)

    以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...

  4. 实现n皇后问题(回溯法)

    /*======================================== 功能:实现n皇后问题,这里实现4皇后问题 算法:回溯法 ============================= ...

  5. HDU 2553 n皇后问题(回溯法)

     DFS Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Description ...

  6. 8皇后-----回溯法C++编程练习

    /* * 八皇后问题回溯法编程练习 * 在8×8的棋盘上,放置8个皇后,两个皇后之间不能两两攻击 * 也即,直线,垂直45度.135度方向不能出现两个皇后 * * copyright Michael ...

  7. 算法——八皇后问题(eight queen puzzle)之回溯法求解

    八皇后谜题是经典的一个问题,其解法一共有种! 其定义: 首先定义一个8*8的棋盘 我们有八个皇后在手里,目的是把八个都放在棋盘中 位于皇后的水平和垂直方向的棋格不能有其他皇后 位于皇后的斜对角线上的棋 ...

  8. js实现八皇后,回溯法

    八皇后问题:将八个皇后摆在一张8*8的国际象棋棋盘上,使每个皇后都无法吃掉别的皇后,一共有多少种摆法? 两个皇后不能同时在同一行,同一列,和斜对角线的位置上,使用回溯法解决. 从第一行选个位置开始放棋 ...

  9. 回溯法求解n皇后和迷宫问题

    回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...

随机推荐

  1. SQL -------- WHERE子句与AND,OR和NOT运算符结合使用。

    AND, OR and NOT  与 运算符中的且或非的意思相同 WHERE子句可以与AND,OR和NOT运算符结合使用. and 表示 查询的语句必须全部包含and 连接的两个或多个条件 or    ...

  2. Java学习:Junit简介

    Junit简介 概述: JUnit 是用于编写和运行可重复的自动化测试的开源测试框架,这样可以保证我们的代码按预期工作.JUnit 可广泛用于工业和作为支架(从命令行)或IDE(如 IDEA)内单独的 ...

  3. 蒙特卡罗方法、蒙特卡洛树搜索(Monte Carlo Tree Search,MCTS)初探

    1. 蒙特卡罗方法(Monte Carlo method) 0x1:从布丰投针实验说起 - 只要实验次数够多,我就能直到上帝的意图 18世纪,布丰提出以下问题:设我们有一个以平行且等距木纹铺成的地板( ...

  4. 【转】常用PLC通讯协议

    三菱FX系列PLC通讯测试 发送帧(Hex): 起始(STX) 02 命令(CMD) 30 首地址(ADDRESS) 30 30 41 30 字节数(BYTES) 30 31 终止(ETX) 03 校 ...

  5. EF连接mysql,出现A call to SSPI failed错误,解决办法

    我的使用场景是用EF连接AWS的mysql RDS,会偶发性的出现A call to SSPI failed错误, System.AggregateException: One or more err ...

  6. 我遇到的WPF的坑

    转自 林德熙Blog 本文:我遇到的WPF的坑 目录 单例应用在多实例用户无法使用 标记方法被使用 当鼠标滑过一个被禁用的元素时,让ToolTip 显示 获取设备屏幕数量 获取当前域用户 绑定资源文件 ...

  7. 初识Markdown

    目录 一.基础语法 二.语法规则 1.标题 2.列表 3.文字格式 4.链接 5.图片 6.引用 7.水平分隔线 8.代码块 9.表格 10.文档目录 11.转义定义 写在前面 Markdown(简称 ...

  8. ASP.Net Core中设置JSON中DateTime类型的格式化(解决时间返回T格式)

    最近项目有个新同事,每个API接口里返回的时间格式中都带T如:[2019-06-06T10:59:51.1860128+08:00],其实这个主要是ASP.Net Core自带时间格式列化时间格式设置 ...

  9. Postgresql中无则插入的使用方法INSERT INTO WHERE NOT EXISTS

    一.问题 Postgresql中无则插入的使用方法INSERT INTO WHERE NOT EXISTS,用法请参考样例. 二.解决方案 (1)PostgresSQL INSERT INTO tes ...

  10. 《Android开发艺术探索》读书笔记之Activity的生命周期

    两种不同情况下的Activity生命周期 (1)典型情况下的生命周期 指在有用户参与的情况下,Activity所经过的生命周期的改变. (2)异常情况下的生命周期 指Activity被系统回收或者由于 ...