计算机算法中的经典算法之八皇后相关问题
八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。现代教学中,把八皇后问题当成一个经典递归算法例题。
下面我用递归和循环两种方式来加以描述。
1.循环方式:
package EightQueens;
public class EightQueensNotRecursive {
private static final boolean AVAILABLE = true;
private int squares = 8, norm = squares - 1;
private int positionInRow[] = new int[squares];
private int p=-1;
private boolean[] rows = new boolean[squares];
private boolean[] column = new boolean[squares];
private boolean[] leftDiagonal = new boolean[2 * squares - 1];
private boolean[] rightDiagonal = new boolean[2 * squares - 1];
private static int howMany = 0;
public EightQueensNotRecursive() {
// To complete the initialization work for the
// column,leftDiagonal,rigthDiagonal.
for (int i = 0; i < squares; i++) {
rows[i] = AVAILABLE;
column[i] = AVAILABLE;
positionInRow[i] = -1;
}
for (int i = 0; i < 2 * squares - 1; i++) {
leftDiagonal[i] = AVAILABLE;
rightDiagonal[i] = AVAILABLE;
}
}
public void printResults(int[] columns) {
int row, col;
System.out.println("八皇后问题的第 " + howMany + " 种解法");
System.out.print("八皇后问题的结果为:");
for (int e : columns) {
System.out.print(e);
}
System.out.println("\n具体的图示如下图所示:");
for (row = 0; row < squares; row++) {
for (col = 0; col < squares; col++) {
if (col == positionInRow[row]) {
System.out.print("@");
} else {
System.out.print("*");
}
}
System.out.println();
}
System.out.println();
}
public void putQueen()
{
int row=0, col;
while (true)
{
for (col = p + 1; col < squares; col++)
{
if(rows[row]==AVAILABLE&&column[col]==AVAILABLE&&leftDiagonal[row+col]==AVAILABLE&&rightDiagonal[row-col+norm]==AVAILABLE)
{
break;
}
}
//在当前的行里面找到了可以放置皇后的位置
if(col<squares)
{
rows[row]=!AVAILABLE;
column[col]=!AVAILABLE;
leftDiagonal[row+col]=!AVAILABLE;
rightDiagonal[row-col+norm]=!AVAILABLE;
positionInRow[row]=col;
p=col;
}else//如果当前行没办反放置皇后了,那么回溯
{
if(row>0)//到前一行
{
row--;
p=positionInRow[row];
rows[row]=AVAILABLE;
column[p]=AVAILABLE;
leftDiagonal[row+p]=AVAILABLE;
rightDiagonal[row-p+norm]=AVAILABLE;
positionInRow[row]=-1;
continue;
}else
{
break;
}
}
if(row==squares-1)
{
howMany+=1;
printResults(positionInRow);
p=positionInRow[row];
rows[row]=AVAILABLE;
column[p]=AVAILABLE;
leftDiagonal[row+p]=AVAILABLE;
rightDiagonal[row-p+norm]=AVAILABLE;
positionInRow[row]=-1;
continue;
}
else
{
row++;
p=-1;
continue;
}
}
}
public static void main(String args[])
{
EightQueensNotRecursive eightQueens=new EightQueensNotRecursive();
eightQueens.putQueen();
System.out.println("皇后问题一共有"+howMany+"种解法");
}
}
2.递归方式:
package EightQueens;
public class EightQueensRecursive {
private static final boolean AVAILABLE=true;
private int squares=8,norm=squares-1;
private int positionInRow[]=new int[squares];
private boolean[] column=new boolean[squares];
private boolean[] leftDiagonal=new boolean[2*squares-1];
private boolean[] rightDiagonal=new boolean[2*squares-1];
private static int howMany=0;
public EightQueensRecursive(){
//To complete the initialization work for the column,leftDiagonal,rigthDiagonal.
for(int i=0;i<squares;i++){
column[i]=AVAILABLE;
positionInRow[i]=-1;
}
for(int i=0;i<2*squares-1;i++){
leftDiagonal[i]=AVAILABLE;
rightDiagonal[i]=AVAILABLE;
}
}
public void printResults(int[] columns){
int row,col;
System.out.println("八皇后问题的第 "+howMany+" 种解法");
System.out.print("八皇后问题的结果为:");
for(int e:columns){
System.out.print(e);
}
System.out.println("\n具体的图示如下图所示:");
for(row=0;row<squares;row++){
for(col=0;col<squares;col++){
if(col==positionInRow[row]){
System.out.print("@");
}else{
System.out.print("*");
}
}
System.out.println();
}
System.out.println();
}
public void putQueen(int row){
//如果前面已经得到了一个可行解
for(int i=0;i<squares;i++)
{
if(row>squares-1) break;
if(column[i]==AVAILABLE&&leftDiagonal[row+i]==AVAILABLE&&rightDiagonal[row-i+norm]==AVAILABLE)
{
positionInRow[row]=i;
column[i]=!AVAILABLE;
leftDiagonal[row+i]=!AVAILABLE;
rightDiagonal[row-i+norm]=!AVAILABLE;
if(row<squares-1){
putQueen(row+1);
}else
{
howMany+=1;
printResults(positionInRow);
}
column[i]=AVAILABLE;
leftDiagonal[row+i]=AVAILABLE;
rightDiagonal[row-i+norm]=AVAILABLE;
}
}
}
public static void main(String args[]){
EightQueensRecursive eightQueens=new EightQueensRecursive();
eightQueens.putQueen(0);
System.out.println("皇后问题一共找到了 "+howMany+"组解。");
}
}