n皇后问题要求在一个n×n格的棋盘上放置n个皇后,使它们彼此不得攻击。按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的任何棋子。因此,n后问题等价于在n×n的棋盘上放置n个皇后,且任何两个皇后不能被放在同一行、同一列或同一斜线上。
二维数组求解n皇后
首先根据我们的一般思路,算法问题大多数归于数组类,那么n皇后问题放到其中,便可由一个二维数组(a[i][j],i<n,j<n)分别代表n皇后放置的行列数来解决。
1.不同行
不同行 = n皇后所有的行数i不能相同
2.不同列
不同列 = n皇后所有的列数j不能相同
3.不在同一斜线上
这个貌似不能直接看出来了。那么,我们来张直观点的图
中间的点相当于一个皇后,在这里我们把它看成一个点坐标,以这个点坐标为原点可做一个坐标轴,同行相当于x轴、同列相当于y轴,而同斜线就相当于两条直线,这两条直线对应的函数表达式是:y = ±x 。
y = ±x 这个函数的图形特点是,直线上各点的横坐标长度每增加m,则纵坐标长度也增加m,即所有点之间的“横坐标长度之差” = “纵坐标长度之差”
(这里也可以不把当前皇后的位置设为原点,那么同斜线上的点依然满足 “横坐标长度之差” = “纵坐标长度之差” 或 某一个点自身的 ”横纵坐标之差的绝对值“ = 另一点的“横纵坐标之差的绝对值”,因为它们的斜率总为 ±1)
上边只是对 y = ± x 这条直线的特点分析,看不懂的没有关系,只要知道下面的结论就行了。
结论:假设两个皇后的位置分别为 a[i1][j1]、a[i2][j2],那么,如果两个皇后在同一条斜线上,则 | i1 - i2 | = | j1 - j2 | (或| i1 - j1 | = | j1 - j2 |,两个式子效果相同)
以上就是对n皇后问题需要满足的条件分析,用二维数组解n皇后问题的一个程序如下
import java.util.*;
//n皇后解法
public class Queen {
private static Scanner keyboard; //键盘输入值
int checkboard[][]; //一个二维数组表示棋盘
int count = 0; //一共有多少种方法
public static void main(String[] args)
{
int nums = getnumbers(); //获取皇后数量
Queen Queens = new Queen(nums); //初始化棋盘
Queens.putQueen(nums); //往棋盘上放置皇后
System.out.print("There are total " + Queens.count + " methods"); //输出有多少种方法
}
//初始化棋盘
public Queen(int nums)
{
checkboard = new int[nums][nums];
}
//往棋盘上放置皇后
public void putQueen(int QueenNums)
{
if (QueenNums == 0)
displayword();
else
for (int i = 0; i < checkboard.length;)
{
if (checkEmpty(QueenNums - 1, i) == true) {
checkboard[i][QueenNums - 1] = 1;
putQueen(QueenNums - 1);
} else {
checkboard[i][QueenNums - 1] = 0;
i++;
}
}
}
//输出皇后位置
public void displayword()
{
count++;
System.out.println("Methods " + count);
//输出符合条件的皇后位置(0为空,1为放置皇后的位置)
for (int i = 0; i < checkboard.length; i++) {
for (int j = 0; j < checkboard.length; j++)
System.out.print(checkboard[i][j] + " ");
System.out.println();
}
}
//获取输入值,输入值为皇后的数量
public static int getnumbers()
{
keyboard = new Scanner(System.in); //获取控制台的输入
System.out.println("please enter the numbers of Queens");
return keyboard.nextInt(); //返回皇后的数量
}
//检查该位置是否为空
public boolean checkEmpty(int col, int row)
{
int DiagnoseUpRow = row, DiagnoseDownRow = row;
//当列值比棋盘的总长度小时
while (col < checkboard.length) {
if (DiagnoseUpRow >= 0 && checkboard[DiagnoseUpRow][col] == 1)
return false;
if (DiagnoseDownRow < checkboard.length && checkboard[DiagnoseDownRow][col] == 1)
return false;
if (checkboard[row][col] == 1)
return false;
col++;
DiagnoseUpRow--;
DiagnoseDownRow++;
}
return true;
}
}
效果:4皇后的位置
二维数组可以用来求解n皇后,但是效率不高,程序中做了很多没必要的判断。
一维数组求解n皇后
现在我们知道,n皇后在放置时是不同行也不同列的,那么我们就可以把二维数组的表示法压缩成一维数组a[n]。在这个数组中,n表示皇后所在的行,n不会相同,则满足了不同行的条件;a[n]的值表示皇后所在的列,要想满足不同列的条件,则数组的值不能相等;接下来便是不在同一斜线上,这个根据上边已经分析过了,需要满足abs(i - row) != abs(a[i] - col)。三个条件齐全后,皇后的位置便确定了。