回溯法 | 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皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...
随机推荐
- SWIG 3 中文手册——6. SWIG 和 C++
目录 6 SWIG 和 C++ 6.1 关于包装 C++ 6.2 方法 6.3 支持的 C++ 功能 6.4 命令行选项与编译 6.5.1 代理类的构造 6.5.2 代理类中的资源管理 6.5.3 语 ...
- SQL-----数据库三种删除方式详解
第一种 使用delete 语句 特点: delete 属于数据库操纵语言DML,表示删除表中的数据, 删除过程是每次从表中删除一行,并把该行删除操作作为事务记录在日志中保存 可以配合事件(tran ...
- 常见的Redis面试"刁难"问题,值得一读
Redis有哪些数据结构? 字符串String.字典Hash.列表List.集合Set.有序集合SortedSet. 如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog.G ...
- 【51nod1355】斐波那契的最小公倍数(min-max容斥)
[51nod1355]斐波那契的最小公倍数(min-max容斥) 题面 51nod 题解 显然直接算还是没法算的,所以继续考虑\(min-max\)容斥计算. \[lcm(S)=\prod_{T\su ...
- 11、VUE混合
1.混合的概念(mixture) 混合是以一种灵活的方式,为组件提供代码复用功能.(类似于封装) 混合对象可以包含任意的组件选项.当组件使用了混合对象时,混合对象的所有选项将被“混入”组件自己的选项中 ...
- 看一下“Dubbo 2.7”的三大新特性
Dubbo 2.7.x 作为 Apache 的孵化版本,除了代码优化之外,还新增了许多重磅的新特性,本文将会介绍其中最典型的三个新特性: 一.异步化改造 二.三大中心改造 三.服务治理增强 一.异步支 ...
- .NetCore之基础
.NetCore几大特点 这篇文章主要从.NetCore全面开源.依赖注入.包引入.跨平台.应用服务器的特点来入手.大约需要10分钟的阅读时间. 与.Net的区别 在.Net与.NetCore在代码编 ...
- 学习笔记之知识图谱 (Knowledge Graph)
Knowledge Graph - Wikipedia https://en.wikipedia.org/wiki/Knowledge_Graph The Knowledge Graph is a k ...
- 【案例】电子生产中的排程问题如何解决?APS助力智能化排产
共进电子是典型的消费类电子制造企业,以ODM业务为主,立足双O(OEM/ODM),发展自主品牌.其中,生产模式特点包括: 批量制造.多品种小批量.面向订单生产: 产品结构复杂,设计变更频繁:生产计划复 ...
- Myapp
一.github地址:https://github.com/jianghailing/rjgcsecondwork 二.PSP表格: PSP2.1 Personal Software Process ...