递归算法
1 package com.test.spring.mytag; 2 3 public class Queen { 4 // 皇后个数 5 static int SIZE = 8; 6 // 一共有多少种解法 7 static int count = 0; 8 // 表示解的数组,比如queen[0]=0,表示解的第0行第0列放置了皇后,如果使用二维数组,内存占用将会是一维数组的N倍 9 static int queen[] = new int[SIZE]; 10 11 /** 12 * 检查第row行第queen[row]列是否可以放置queen,以下三种情况之一不能放置queen 13 * 1.其他行的queen[row]列不能放置queen,即queen[i]不能等于queen[row] 14 * 2.queen[row]所在位置的主对角线不能放置queen,主对角线元素的特征是横坐标减去纵坐标所得的结果相同 15 * 3.queen[row]所在位置的副队角线不能防止queen,副对角线元素的特征是横坐标加上纵坐标所得的结果相同 16 */ 17 static boolean check(int row) { 18 for (int i = 0; i < queen.length && i != row; i++) { 19 if (queen[i] == queen[row] || i - queen[i] == row - queen[row] || i + queen[i] == row + queen[row]) { 20 return false; 21 } 22 } 23 return true; 24 } 25 26 // 处理第row行 27 static void process(int row) { 28 if (row == SIZE) { 29 show(); 30 count++; 31 } else { 32 for (int column = 0; column < queen.length; column++) { 33 queen[row] = column; 34 if(check(row)) { 35 process(row+1); 36 } 37 } 38 } 39 } 40 41 static void queen() { 42 process(0); 43 } 44 45 static void show() { 46 System.out.println("***********************"); 47 for (int i = 0; i < 8; i++) { 48 for (int j = 0; j < 8; j++) { 49 if (queen[i] == j) { 50 System.out.print(" Q "); 51 } else { 52 System.out.print(" . "); 53 } 54 } 55 System.out.println(); 56 } 57 System.out.println("***********************"); 58 } 59 60 public static void main(String[] args) { 61 queen(); 62 System.out.println(count); 63 } 64 }
程序第34行,只考虑了检查通过的情况,没有在检查失败之后进行queen[row] = 0以重置检查失败的行,这是因为check函数的循环条件,即第18行的
i < queen.length && i != row
已经限定了,即每一行只考虑是否兼容于其之前的那些行,不需要考虑后面的行,当然这个条件其实应该改一下,改成 i < row就可以了
c++版,可以看到解的运算过程
#include<iostream> #include<windows.h> using std::cin; using std::cout; using std::endl; class Queen { private: //皇后个数 const int SIZE = 8; //表示解的数组,比如queen[0]=0,表示解的第0行第0列放置了皇后,如果使用二维数组,内存占用将会是一维数组的N倍 int queen[8] = { 0 }; //尝试次数 int tried = 1; //解的个数 int count = 0; public: //直观展示皇后的放置情况,row代表当前处理到第几行,只是为了debug方便 void show(int row) { Sleep(1000); system("cls"); cout << "row: " << row << " column: " << queen[row] << endl; cout << "tried: " << tried << endl; cout << "found: " << count << endl; for (size_t row = 0; row < SIZE; row++) { for (size_t column = 0; column < SIZE; column++) { if (queen[row] == column) { cout << " Q "; } else { cout << " . "; } } cout << endl; } } /** * 检查第row行第queen[row]列是否可以放置queen,以下三种情况之一不能放置queen * 1.其他行的queen[row]列不能放置queen,即queen[i]不能等于queen[row] * 2.queen[row]所在位置的主对角线不能放置queen,主对角线元素的特征是横坐标减去纵坐标所得的结果相同 * 3.queen[row]所在位置的副队角线不能防止queen,副对角线元素的特征是横坐标加上纵坐标所得的结果相同 */ bool check(int row) { tried++; show(row); for (int i = 0; i < SIZE && i != row; i++) { if (queen[i] == queen[row] || i - queen[i] == row - queen[row] || i + queen[i] == row + queen[row]) { return false; } } return true; } //处理第row行 void process(int row) { if (row == SIZE) { count++; cout << "按回车继续寻找下一个解" << endl; if (cin.get() != '\n') { return; } } else { for (size_t column = 0; column < SIZE; column++) { queen[row] = column; if (check(row)) { process(row + 1); } /*else { queen[row] = 0; }*/ } } } void start() { process(0); cout << "一共有 " << count << " 个解" << endl; } }; int main(void) { Queen queen; queen.start(); system("pause"); return 0; }