import java.util.Date;
public class Queen {
private final int size;//棋盘的大小,也表示皇后的数目
private int[] location;//皇后在棋盘的每行上的列的位置
private int[] colsOccupied;//皇后在棋盘上占据的列
private int[] cross1Occupied;//皇后在棋盘上占据的正对角线
private int[] cross2Occupied;//皇后在棋盘上占据的反对角线
private static int count;//解决方案的个数
private static final int STATUS_OCCUPIED = 1;//占领状态
private static final int STATUS_OCCUPY_CANCELED = 0;//未占领状态
public Queen(int size){
this.size = size;
location = new int[size];
colsOccupied = new int[size];
cross1Occupied = new int[2*size-1];
cross2Occupied = new int[2*size-1];
}
private void printLocation(){
System.out.println("以下是皇后在棋盘上的第"+count+"种摆放位置");
for(int i = 0; i < size; i++){
System.out.println("行:"+i+"列:"+location[i]);
}
}
/**
* 判断位置(i,j)是否被占领
*/
private boolean isOccupied(int i,int j){
return colsOccupied[j]==0&&cross1Occupied[i-j+size-1]==0&&cross2Occupied[i+j]==0;
}
/**
* 设置占领标识
*/
private void setStatus(int i,int j,int flag){
colsOccupied[j] = flag;//宣布占领或取消占领第j列
cross1Occupied[i-j+size-1] = flag;//宣布占领或取消占领正对角线
cross2Occupied[i+j] = flag;//宣布占领或取消占领反对角线
}
/**
* 从第i行开始放置皇后
*/
private void place(int i){
for(int j = 0; j < size ; j++)//在第i行,分别尝试把皇后放在每一列上
if(isOccupied(i,j)){//判断该位置是否被占领
location[i] = j;//摆放皇后,在第i行把皇后放在第j列
setStatus(i,j,STATUS_OCCUPIED);//宣布占领位置(i,j)
if(i < size-1)
place(i+1);//如果所有皇后没有摆完,递归摆放下一行的皇后
else{
count++;//统计解决方案的个数
printLocation();//完成任务,打印所有皇后的位置
}
setStatus(i, j, STATUS_OCCUPY_CANCELED);//撤销占领位置(i,j)
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
long start = new Date().getTime();
new Queen(5).place(0);
System.out.println("一共找到 "+count+" 种摆放方案");
long end = new Date().getTime();
System.out.println("一共耗时 "+(end-start)+" ms");
}
}
/**
分析:数组int[2*size-1]大小为什么是(2*size-1),为什么判断cross1Occupied[i-j+size-1] == 1与cross2Occupied[i+j] == 1
一种对角线情况如下:
参考点为([row][col]),则与参考点在同一斜线(对角线)的坐标为([row+1][col-1])、([row-1][col+1])、([row-2][col+2])等等
发现规律,横纵座标之和相等。 均为 row+col,由此可以保证该斜线上只能有一个皇后
继续考虑 row+col 之和的大小,取两种极限情况:即int[0][0]与int[size-1][size-1]
不难判断 row+col 之和应该是 0~2*(size-1),即数组长度应该为 (2*size-1)
因为还有一个0,所以为 2*(size-1) + 1 = (2*size-1)
并且判断cross2Occupied[i+j]==1
(因为想在([i][j])位置上放置皇后,所以需要判断与([i][j])点在同一斜线的所有点是否有皇后)
另一种对角线情况如下:
参考点为([row][col]),则与参考点在另外同一斜线(对角线)的坐标为([row+1][col+1])、([row-1][col-1])、([row-2][col-2])等等
发现规律,横纵座标之差相等。 均为 row-col,由此可以保证该斜线上只能有一个皇后
继续考虑 row-col 之差的大小,取两种极限情况:即int[0][size-1]与int[size-1][0]
差值最小为 0-(size-1) = -size+1 差值最大为 size-1-0=size-1
数组个数 (size-1) - (-size+1) = 2*size-2,因为还有一个0,所以为 2*size-2 + 1 = (2*size-1)
row-col 作为数组下标,因此不能为负数。cross1Occupied[i-j]的下标为负数(-size+1),所以cross1Occupied
数组应该写成 [i-j+size-1],以保证下标从0开始,并且判断cross1Occupied[i-j+size-1] == 1
(因为想在([i][j])位置上放置皇后,所以需要判断与([i][j])点在另一同一斜线的所有点是否有皇后)
*/
public class Queen {
private final int size;//棋盘的大小,也表示皇后的数目
private int[] location;//皇后在棋盘的每行上的列的位置
private int[] colsOccupied;//皇后在棋盘上占据的列
private int[] cross1Occupied;//皇后在棋盘上占据的正对角线
private int[] cross2Occupied;//皇后在棋盘上占据的反对角线
private static int count;//解决方案的个数
private static final int STATUS_OCCUPIED = 1;//占领状态
private static final int STATUS_OCCUPY_CANCELED = 0;//未占领状态
public Queen(int size){
this.size = size;
location = new int[size];
colsOccupied = new int[size];
cross1Occupied = new int[2*size-1];
cross2Occupied = new int[2*size-1];
}
private void printLocation(){
System.out.println("以下是皇后在棋盘上的第"+count+"种摆放位置");
for(int i = 0; i < size; i++){
System.out.println("行:"+i+"列:"+location[i]);
}
}
/**
* 判断位置(i,j)是否被占领
*/
private boolean isOccupied(int i,int j){
return colsOccupied[j]==0&&cross1Occupied[i-j+size-1]==0&&cross2Occupied[i+j]==0;
}
/**
* 设置占领标识
*/
private void setStatus(int i,int j,int flag){
colsOccupied[j] = flag;//宣布占领或取消占领第j列
cross1Occupied[i-j+size-1] = flag;//宣布占领或取消占领正对角线
cross2Occupied[i+j] = flag;//宣布占领或取消占领反对角线
}
/**
* 从第i行开始放置皇后
*/
private void place(int i){
for(int j = 0; j < size ; j++)//在第i行,分别尝试把皇后放在每一列上
if(isOccupied(i,j)){//判断该位置是否被占领
location[i] = j;//摆放皇后,在第i行把皇后放在第j列
setStatus(i,j,STATUS_OCCUPIED);//宣布占领位置(i,j)
if(i < size-1)
place(i+1);//如果所有皇后没有摆完,递归摆放下一行的皇后
else{
count++;//统计解决方案的个数
printLocation();//完成任务,打印所有皇后的位置
}
setStatus(i, j, STATUS_OCCUPY_CANCELED);//撤销占领位置(i,j)
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
long start = new Date().getTime();
new Queen(5).place(0);
System.out.println("一共找到 "+count+" 种摆放方案");
long end = new Date().getTime();
System.out.println("一共耗时 "+(end-start)+" ms");
}
}
/**
分析:数组int[2*size-1]大小为什么是(2*size-1),为什么判断cross1Occupied[i-j+size-1] == 1与cross2Occupied[i+j] == 1
一种对角线情况如下:
参考点为([row][col]),则与参考点在同一斜线(对角线)的坐标为([row+1][col-1])、([row-1][col+1])、([row-2][col+2])等等
发现规律,横纵座标之和相等。 均为 row+col,由此可以保证该斜线上只能有一个皇后
继续考虑 row+col 之和的大小,取两种极限情况:即int[0][0]与int[size-1][size-1]
不难判断 row+col 之和应该是 0~2*(size-1),即数组长度应该为 (2*size-1)
因为还有一个0,所以为 2*(size-1) + 1 = (2*size-1)
并且判断cross2Occupied[i+j]==1
(因为想在([i][j])位置上放置皇后,所以需要判断与([i][j])点在同一斜线的所有点是否有皇后)
另一种对角线情况如下:
参考点为([row][col]),则与参考点在另外同一斜线(对角线)的坐标为([row+1][col+1])、([row-1][col-1])、([row-2][col-2])等等
发现规律,横纵座标之差相等。 均为 row-col,由此可以保证该斜线上只能有一个皇后
继续考虑 row-col 之差的大小,取两种极限情况:即int[0][size-1]与int[size-1][0]
差值最小为 0-(size-1) = -size+1 差值最大为 size-1-0=size-1
数组个数 (size-1) - (-size+1) = 2*size-2,因为还有一个0,所以为 2*size-2 + 1 = (2*size-1)
row-col 作为数组下标,因此不能为负数。cross1Occupied[i-j]的下标为负数(-size+1),所以cross1Occupied
数组应该写成 [i-j+size-1],以保证下标从0开始,并且判断cross1Occupied[i-j+size-1] == 1
(因为想在([i][j])位置上放置皇后,所以需要判断与([i][j])点在另一同一斜线的所有点是否有皇后)
*/