要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。
问共有多少种不同的方法?
解题思路:通过一个int[8][8]的二位数组构建棋盘,初始化为0,我们可以定义如果该位置摆放了皇后那么该位置对应的二维数组被置为-1。因为皇后之间不能相互攻击,所以我们要明确指出该皇后的影响范围,于是我们采用将该皇后能影响到的棋盘位置全部+1,比如:
-11111111
11000000
10100000
10010000
10001000
10000100
10000010
10000001
这样我们就可以判断,只要是0的地方就可以放置皇后,只要是-1就是皇后的位置,只要是大于0的地方就是被皇后影响的地方。这样做有个什么好处呢,就是我们再回溯时只需要通过简单的对皇后的影响范围进行-1就可以取消她的影响范围了。下面直接贴出代码,后面有注释。如果读者有什么疑惑可以给我留言~~
<pre name="code" class="java">public class Main {
static int[][] Arr = new int[8][8];
static int Count=0;
public static void main(String[] args){
Cal(0,0);//递归函数,传入当前选中位置是第几行第几列
System.out.println(Count);
}
public static void Cal(int a,int b){
if(a==8){
Count++;
for(int j=0;j<8;j++){//寻找第8行已经摆放了的皇后的位置
if(Arr[7][j]==-1){
Sub(7,j);//找到后拿掉皇后,并且取消掉该皇后的影响
return;
}
}
}
else{
boolean Flag=true;//设置一个标志位,用来判断该行是否还有可以摆放皇后的位置
for(int i=0;i<8;i++){
if(Arr[a][i]==0){
Flag=false;//若有可以摆放皇后的位置,将标志位置为false
Add(a,i);//摆放这个皇后,并且添加该皇后的影响
Cal(a+1,i);//将下一个状态带入状态方程
}
}
if(Flag==true){//如果没有找到可以摆放皇后的位置,就取消掉上一层的皇后的位置,并且消除该皇后的影响
Sub(a-1,b);
return;
}
if(Flag==false&&a>0){//如果有改层有可以摆放皇后的位置,就要在回溯时拿掉该皇后,并且取消该皇后的影响
for(int i=0;i<8;i++){
if(Arr[a-1][i]==-1){
Sub(a-1,i);
return;
}
}
}
return;
}
}
public static void Add(int x,int y){//添加皇后,并且添加该皇后的影响
Arr[x][y]=-1;
for(int i=0;i<8;i++){
if(i!=y)
Arr[x][i]=Arr[x][i]+1;
}
for(int i=0;i<8;i++){
if(i!=x)
Arr[i][y]=Arr[i][y]+1;
}
for(int i=-7;i<8;i++){//左上到右下
if((i+x)>=0&&(i+x)<8&&i!=0&&(i+y)>=0&&(i+y)<8){
Arr[x+i][y+i]=Arr[x+i][y+i]+1;
}
}
for(int i=-7;i<8;i++){//左下到右上
if((x-i)>=0&&(x-i)<8&&i!=0&&(i+y)>=0&&(i+y)<8){
Arr[x-i][y+i]=Arr[x-i][y+i]+1;
}
}
}
public static void Sub(int x,int y){//消去该皇后的影响
Arr[x][y]=0;
for(int i=0;i<8;i++){
if(i!=y)
Arr[x][i]=Arr[x][i]-1;
}
for(int i=0;i<8;i++){
if(i!=x)
Arr[i][y]=Arr[i][y]-1;
}
for(int i=-7;i<8;i++){//左上到右下
if((i+x)>=0&&(i+x)<8&&i!=0&&(i+y)>=0&&(i+y)<8){
Arr[x+i][y+i]=Arr[x+i][y+i]-1;
}
}
for(int i=-7;i<8;i++){//左下到右上
if((x-i)>=0&&(x-i)<8&&i!=0&&(i+y)>=0&&(i+y)<8){
Arr[x-i][y+i]=Arr[x-i][y+i]-1;
}
}
}
}