皇后是国际象棋中威力最大的棋子。在下面所示的棋盘上,皇后可以攻击位于箭头所覆盖位置的所有棋子。我们能不能把N个皇后放在棋盘(N×N)上,它们中的任何一个都无法攻击其余的皇后?请编写程序输出皇后的摆放方案,并找出一共有几种方法。
分析:如果我们逐行放置皇后,就不会有皇后处于同一行,只需要判断是否在同一列或是对角线上就可以了,那接下来的问题就是如何判断是否在同一列或是对角线上,我们可以用一个整数表示行数的变化,用一个数组记录列数的变化,数组的下标为行数,这样就可表示某一行列数的变化,这样我们可以用数组的值来判断两个皇后是否处于一列,用两个皇后的行数差是否等于列数差来判断两个皇后是否处于对角线上,如何判断这个问题解决后就是根据顺序遍历每一行,记录解法数。
import java.util.*;
public class n皇后问题_解法二 {
static int n,count=0;
static int[] a=new int[100]; //表示列数
public static boolean p(int k) {
for(int i=1;i<k;i++)
if(a[i]==a[k]||k-i==Math.abs(a[i]-a[k]))
return false;
return true;
}
public static void f() {
int k=1;
while(k>=1) {
a[k]=a[k]+1; //从不同的列开始查起
while(a[k]<=n&&!p(k)) //如果该列不能放置皇后,下一列
a[k]=a[k]+1;
if(k==n&&a[k]<=n) { //如果每一行都放置了皇后,并且列数的结果也在范围中,结果加一
count++;
}else if(k<n&&a[k]<=n) { //如果还有行没有放置皇后,那就继续在下一行放置皇后
k=k+1;
}else { //如果所有的行都放置了皇后,但列数不在范围内,回溯到上一行继续放置
a[k]=0;
k=k-1;
}
}
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
f();
System.out.println(count);
}
}
分析:除了上面的一般的解法外,也可以采用如下解法:对于位置(x,y)来说,x+y表示的该位置的副对角线,y-x表示就是该位置的主对角线。如下图所示,y-x的值在某一位置的主对角线上是相同的,x+y的值在某一位置的副对角线上是相同的。根据此规律我们可以第一个二维数来存储每一个位置上否能放置皇后,例:定义v[][],其中v[0][i]表示某一列否放置皇后,v[1][i]表示 主对角线,v[2][i]表示副对角线,能放置皇后时数组v的值为0,否则为1。
import java.util.*;
public class n皇后问题 {
static int count=0,n;
public static void dfs(int[][] v,int k) {
if(k==n)
count++;
for(int i=0;i<n;i++) {
if(v[0][i]==0&&v[1][k-i+n]==0&&v[2][k+i]==0) {
v[0][i]=1;
v[1][k-i+n]=1;
v[2][k+i]=1;
dfs(v,k+1);
v[0][i]=0;
v[1][k-i+n]=0;
v[2][k+i]=0;
}
}
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
int[][] v=new int[3][2*n+1];
dfs(v,0);
System.out.println(count);
}
}