前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >(Java实现) N皇后问题[通俗易懂]

(Java实现) N皇后问题[通俗易懂]

作者头像
全栈程序员站长
发布2022-11-11 15:13:30
8210
发布2022-11-11 15:13:30
举报
文章被收录于专栏:全栈程序员必看

n皇后问题是一个以国际象棋为背景的问题:在n×n的国际象棋棋盘上放置n个皇后,使得任何一个皇后都无法直接吃掉其他的皇后,即任意两个皇后都不能处于同一条横行、纵行或斜线上。

蛮力法思想:


解决n皇后问题的思想本质上就是蛮力法,生成所有可能的摆放情况,并判断该情况是否满足要求,我们以树结构来表示解决问题的方法。以4*4的棋盘为例,第0层的根节点为空白的棋盘,第1层为只在棋盘的第一行摆放的四种不同情况,第2层是在第1层的基础上,摆放第二行的棋子,最后的叶子结点便是所有可能的完整摆放情况,共256种,但加上中途生成的不完整情况共1+4+16+64+256=340种。

在这里插入图片描述
在这里插入图片描述

回溯法思想:


回溯法其实是以蛮力法为基础,只是不需要生成所有的情况,我们可以发现,在整棵树中,有些棋盘的摆放情况在未达到叶子结点时,便已经不满足n皇后的条件了,那么我们就没有必要再去往下摆放棋子(生成下一层的结点),而是直接回到该结点的父节点,生成新的情况进行判断。通过这种方法可以减少生成完全树中的一些不必要的子树,我们称之为“剪枝”。具体实现中回溯法与蛮力法的主要区别在于判断棋盘的代码所在的位置,蛮力法在摆放完所有皇后后再判断,回溯法在每摆放好一个皇后时就进行判断。

在这里插入图片描述
在这里插入图片描述

具体实现:


根据n皇后问题的规模,创建大小为n的数组代替树结构,使其下标代表行数,内容代表列数,数组中的每个数必定位于不同的行,数组内容不同证明两个元素位于不同的列,两数下标的差的绝对值不等于两数内容的差的绝对值,表示两数不位于同一斜线上。

代码语言:javascript
复制
import java.util.Arrays;
import java.util.Scanner;
public class Nhuanghouwenti {
private static int queenNum;//皇后的个数  
private static int[] hash;//下标表示i号皇后(皇后i放在第i行)value表示放的列号  
private static int count = 0;//合法摆放方式的个数  
public static void placeQueen(int m) {  
if (m > queenNum) {//如果摆到了n+1行了,说明前n行都是不冲突的,合法的  
count++;  
for (int i = 1; i <=queenNum; i++) {
System.out.print(hash[i]);
}
System.out.println();
//	            System.out.println(Arrays.toString(hash));  
//打印合法的摆放结果  
//	            for(int i = 1; i <= queenNum; i++){  
//	                int column = hash[i];//hash值表示皇后i所在的列号  
//	                for(int j = 1; j <= queenNum ;j++){  
//	                    if(j!= column){  
//	                        System.out.print("* ");  
//	                    }else{  
//	                        System.out.print("Q ");  
//	                    }  
//	                }  
//	                System.out.println();  
//	            }  
return;  
}  
for (int i = 1; i <= queenNum; i++) {  
//check the column is conflict with former ones or not  
//if so, check the next column until find a non-conflict column   
//or until the last column ,return;  
if (isConfilct(m, i)) {   
continue;  
} else {//如果检测到第i列不冲突,是安全的,  
hash[m] = i;//将皇后m放在第i列  
placeQueen(m + 1);//再放皇后m+1,  
//如果皇后m+1放完并返回了  
//两种可能:  
//1:冲突,返回了  
//2.一直将所有的皇后全部放完并安全返回了  
//将皇后m回溯,探索新的可能或者安全的位置  
hash[m] = -1;  
//其实这里没必要将m重新赋值的,因为检测到下一个  
//安全位置的时候会把hash[m]覆盖掉的  
//但是为了更好的体现“回溯”的思想,在这里画蛇添足了  
}  
}  
}  
/** 
* 检测冲突 
* @param index 
*            表示行号 
* @param hash 表示第i行放置皇后的列数
*            值表示列号 
* @return 
*/  
private static boolean isConfilct(int row, int column) {  //一行一个皇后,第n个皇后也代表着第n行
if(row == 1){//第1行永远不会冲突  
return false;  
}  
//只需要保证与那些已经就位的皇后不冲突即可  
for (int i = 1; i < row; i++) {  //当前的行数
if (hash[i] == column || ( column - row) == (hash[i] - i) || (row - column)== (i-hash[i])   //以前行数减列数与现在的是否相等
|| (row + column) == (hash[i] + i)) {  
return true;  
}  
}  
return false;  
}  
public static void main(String[] args) {  
Scanner sc = new Scanner(System.in);  
queenNum = sc.nextInt();  
hash = new int[queenNum + 1];  
for (int i = 0; i < hash.length; hash[i++] = -1);//初始化棋盘  
placeQueen(1);  
System.out.println(count);  
}  
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/187486.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月30日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档