今早上看了一篇英语阅读之后,莫名有些空虚寂寞冷。拿出算法书,研读回溯法。我觉得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. php 500报错解决方案

    php 500报错解决方案 1 先看nginx error.log 指定的错误日记文件路径 找到这个日记文件看 里面信息 2 再看 php-fpm.conf 里面指定的PHP错误日记的路径 具体如下& ...

  2. Window 远程桌面漏洞风险,各个厂家的扫描修复方案(CVE-2019-0708)

    自微软公司于2019年5月14日发布远程桌面服务远程代码执行漏洞(CVE-2019-0708)安全公告后,整个业界都一直在密切关注,这个漏洞编号必将在当今网络中掀起腥风血雨.各大厂商也纷纷推出自己的修 ...

  3. 微信小程序练习笔记(更新中。。。)

    微信小程序练习笔记 微信小程序的练习笔记,用来整理思路的,文档持续更新中... 案例一:实现行的删除和增加操作  test.js // 当我们在特定方法中创建对象或者定义变量给与初始值的时候,它是局部 ...

  4. golang学习笔记 --flag

    概述 flag包提供了一系列解析命令行参数的功能接口 命令行语法 命令行语法主要有以下几种形式 -flag //只支持bool类型 -flag=x -flag x //只支持非bool类型 以上语法对 ...

  5. 关于NB-IoT,没有比这篇更通俗易懂的啦!

    来源:内容来自「鲜枣课堂」,谢谢. 大家好,我是小枣君. 今天,我是来“吹NB”的.嗯,标题已经剧透了,这个NB,就是NB-IoT. 在过去的一年多,NB-IoT真的可以说是大红大紫.在通信圈里,除了 ...

  6. 【linux】CentOS 查看系统时间,修改时区

    ===============CentOS 7.6================ 1.查看系统时间 date 查看当前系统时间以及时区结果是: Mon Jul 8 09:23:31 UTC 2019 ...

  7. html提示信息框淡入淡出效果(自己的思路,如果有更好的思路,请留言)

    使用方法: 调用initMessagebox(“要显示的文字”)方法即可 <!--信息框--> <div id="messagebox"></div& ...

  8. chrome(谷歌)浏览器字体发虚解决办法

    chrome(谷歌浏览器)浏览网页时,字体发虚的解决办法: 1.点击chrome里的 “设置” - 外观 - 字体,改为 微软雅黑,该方法测试无效. 2.将系统字体的pingfang字体卸载,完美解决 ...

  9. android版本对应表

    API Level 最初Android版本 Linux内核版本 首次发布日期 后续Android版本 28 9 Unknown 2018-07-02(Beta 3) - 27 8.1 4.10 201 ...

  10. C#实现outlook自动签名

    Outlook下实现自动签名的方式   网上找到一篇资料是在outlook里用vba实现的,但是这样实现的方式由于数字认证的问题不便于部署 在此介绍一种C#下实现的方式,目前确定的outlook版本为 ...