回溯法 | n皇后问题
今早上看了一篇英语阅读之后,莫名有些空虚寂寞冷。拿出算法书,研读回溯法。我觉得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皇后问题的更多相关文章
- 八皇后问题-回溯法(MATLAB)
		
原创文章,转载请注明:八皇后问题-回溯法(MATLAB) By Lucio.Yang 1.问题描述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后,使其不能 ...
 - Java算法——回溯法
		
回溯法一种选优搜索法,又称试探法.利用试探性的方法,在包含问题所有解的解空间树中,将可能的结果搜索一遍,从而获得满足条件的解.搜索过程采用深度遍历策略,并随时判定结点是否满足条件要求,满足要求就继续向 ...
 - 回溯法解决N皇后问题(以四皇后为例)
		
以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...
 - 实现n皇后问题(回溯法)
		
/*======================================== 功能:实现n皇后问题,这里实现4皇后问题 算法:回溯法 ============================= ...
 - HDU 2553   n皇后问题(回溯法)
		
DFS Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Description ...
 - 8皇后-----回溯法C++编程练习
		
/* * 八皇后问题回溯法编程练习 * 在8×8的棋盘上,放置8个皇后,两个皇后之间不能两两攻击 * 也即,直线,垂直45度.135度方向不能出现两个皇后 * * copyright Michael ...
 - 算法——八皇后问题(eight queen puzzle)之回溯法求解
		
八皇后谜题是经典的一个问题,其解法一共有种! 其定义: 首先定义一个8*8的棋盘 我们有八个皇后在手里,目的是把八个都放在棋盘中 位于皇后的水平和垂直方向的棋格不能有其他皇后 位于皇后的斜对角线上的棋 ...
 - js实现八皇后,回溯法
		
八皇后问题:将八个皇后摆在一张8*8的国际象棋棋盘上,使每个皇后都无法吃掉别的皇后,一共有多少种摆法? 两个皇后不能同时在同一行,同一列,和斜对角线的位置上,使用回溯法解决. 从第一行选个位置开始放棋 ...
 - 回溯法求解n皇后和迷宫问题
		
回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...
 
随机推荐
- python3 四舍五入(0.5可以进1)
			
今天做了一个题要求四舍五入,然后找了一个方法:round()可以四舍五入, 试了试1.5--->2 试了试0.5--->0 !!!! 找了几个方法说可以的: # 方法一: from _ ...
 - loonflow 工单系统
			
该项目是基于django的工作流引擎,工单.项目托管在 Github 一.安装基础环境 1.1 安装python 和 pip yum install -y epel-release yum insta ...
 - html 四种定位含义
			
技术过段时间不用的话就会忘记,需要复习一下 1.static:默认值.没有定位,元素出现在正常的流中(忽略top,bottom,left,right或者z-index声明). 2.relative:生 ...
 - 云原生生态周报 Vol. 16 | CNCF 归档 rkt,容器运行时“上古”之战老兵凋零
			
作者列表:木苏,临石,得为,等等 业界要闻 安全漏洞 CVE-2019-9512 CVE-2019-9514 http2 的 DOS 漏洞,一旦攻击成功会耗尽服务器的 cpu/mem,从而导致服务不可 ...
 - Linux常用命令:fdisk mkfs mount umount fstab实现自动挂载
			
写在前 记录点常用命令,fdisk mkfs mount和umount,以及fstab实现自动挂载 fdisk fdisk主要用于操作硬盘的分区表.分区,下面简单记一点最常用的部分 查看当前系统识别到 ...
 - python]用eval强制将字符串转换为字典变量时候出错:NameError: name 'null' is not defined[python]用eval函数 字符串转dict
			
本博客已搬家至个人网站 在路上 - On the way 下面的 技术 分类. 你可以通过点击 更新帖子 [已解决]Python中,用eval强制将字符串转换为字典变量时候出错:NameError: ...
 - 《 .NET并发编程实战》实战习题集 - 3 - CRUD项目中使用FP
			
先发表生成URL以印在书里面.等书籍正式出版销售后会公开内容.
 - java8 Lambda 表达式和函数式接口快速理解
			
前言 接上篇文章 java8 新特性 由于上篇过于庞大,使得重点不够清晰,本篇单独拿出 java8 的 Lambda 表达式和函数式接口说明. Lambda 表达式 lambda 表达式其实就是使用了 ...
 - Java 函数式编程--流操作
			
GitHub Page: http://blog.cloudli.top/posts/Java-函数式编程-流操作/ 外部迭代到内部迭代 在使用集合类时,通用的方式是在使用 for 循环集合上进行迭代 ...
 - WPF 精修篇 属性动画
			
原文:WPF 精修篇 属性动画 属性动画 是通过 Storyboard 来改变属性值 <Rectangle x:Name="rect" Width="200&quo ...