回溯法 | 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皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...
随机推荐
- 第八节:EF Core连接MySql数据库
一. 前提 1.安装EF Core连接MySQL的驱动,这里有两类: (1).Oracle官方出品:MySql.Data.EntityFrameworkCore (版本:8.0.17) (2).其他第 ...
- kvm虚拟机的克隆
kvm虚拟机的克隆分为两种情况 (1) KVM主机本机虚拟机直接克隆. (2) 通过复制配置文件与磁盘文件的虚拟机复制克隆(适用于异机的静态迁移). 1. 本机虚拟机直接克隆 (1) 查看虚拟机配置 ...
- Application类-应用程序生命周期
1.创建Application对象 新建WPF程序后,排除掉WPF自动创建的App.xaml,我们自定义一个类,在该类的Main()方法中,创建Application对象,然后调用创建一个窗口对象,最 ...
- Go是如何生活在内存条里的【译】
原文:A visual guide to Go Memory Allocator from scratch (Golang) 当我第一次开始试图了解 Go 的内存分配器时,觉得它真令人抓狂.所有的所有 ...
- 深入理解 Kubernetes 资源限制:CPU
原文地址:https://www.yangcs.net/posts/understanding-resource-limits-in-kubernetes-cpu-time/ 在关于 Kubernet ...
- Delphi - 利用DLL编程控制摄像头实现拍照、录制视频
Delphi利用avicap32.dll编程控制摄像头实现拍照.录制视频 项目需求:平板电脑(Windows系统)一维/二维码扫描功能: 需求分析: 需要扫描一维/二维码时,分两步实现. 第一步,av ...
- English--音标重难点
English|音标重难点 在拥有了,音标的元音与辅音的基础之后,需要对于这些音标进行加以区分,毕竟方言对于口型的影响非常的大. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点 ...
- C# abstract class Interface的介绍
1.基本概念介绍 抽象类: 1.抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法 2.抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类 3.具体 ...
- webpack报错
webpack-dev-server --inline --progress --config build/webpack.dev.conf.js internal/modules/cjs/loade ...
- 【知识点】SPU&SKU
SPU:标准化产品单元 SPU = Standard Product Unit (标准化产品单元),SPU是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该集合描述了一个产品的特性. ...