問題描述:
在8X8格的國際象棋棋盤上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
問題引申:
在n*n格的國際象棋棋盤上擺放n個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
算法思路:
實現一個逐行逐行地放置皇后的函數
在第X行中的一格放上一個皇后
判斷這個皇后和前幾行的皇后等否互相攻擊,如果能則拿起來重新放到下一列,直到不會和前幾行的皇后相互攻擊后,再轉到X+1行繼續放皇后
然后遞歸調用該函數來解該問題。
最初我考慮的是建立一個n*n的數組表示一個棋盤,每個元素代表一個方格,通過不同的值來表示格子有沒有放皇后和會不會被其他皇后攻擊。
后來發現其實完全沒有必要那么復雜_(:з」∠)_。只需要用一維數組就能表示所有皇后的的位置:
int Queen[MAX];
例如Queen[index],index的值表示行數,Queen[index]的值表示列數,那么Queen[3] = 4就表示第三行、第四列有一個皇后。那么通過判斷Queen[i]和Queen[j]的值是否相等就能知道i,j兩個皇后是不是在同一列了。
那么又該怎么判斷i和j兩個皇后是不是在同一斜線上呢?
我想到了中學學到的一元一次函數。
y = a * x + b
a是斜率,b是截距。很容易就知道棋盤中的斜線的斜率全都是1或-1,那么判斷兩個皇后是不是在同一斜線上,只需要判斷b是否相等就行了。
斜率為1時 b = y - x,為-1時, b = y + x 。我用兩個數組分別記錄1和-1的情況:
int PlusB[MAX]; int MinusB[MAX];
Queen[index] = i;
PlusB[index] = index - i;
MinusB[index] = index + i;
那么很容易地,通過判斷PlusB[i]和PlusB[j],MinusB[i]和MinusB[j]是否相等就能知道i,j兩個皇后是不是在同一條斜線上了。
如此,就能得到判斷一個皇后會不會和前幾行的皇后相互攻擊的函數了:
bool Attack( int index ) { for (int i = 0; i < index; i++) if (Queen[i] == Queen[index] || PlusB[i] == PlusB[index] || MinusB[i] == MinusB[index]) return true; return false; }
那么遞歸調用的放置皇后的函數也很輕松地就實現了:
void PutQueen( int index ) { if (index == n) { Result++; return; } for (int i = 0; i < n; i++) { Queen[index] = i; PlusB[index] = index - i; MinusB[index] = index + i; if (!Attack( index )) PutQueen( index + 1 ); } }
通過index表示行數,即在第index行上放置皇后,每次判斷皇后會否互相攻擊,若不會,則index+1后遞歸調用函數,如果會攻擊則換一列放置皇后。直到index == n,則給結果加一並回溯一步換一列放置皇后,或者試完第index行的所有列了,又會回溯到上一步。
整個程序的代碼如下:
1 #include <fstream> 2 3 using namespace std; 4 5 int n = 0; // Number of Queens 6 int Result = 0; 7 const int MAX = 100; 8 int Queen[MAX]; 9 int PlusB[MAX]; 10 int MinusB[MAX]; 11 FILE *fp; 12 13 void OutPut( ); 14 bool Attack( int index ); 15 void PutQueen( int index ); 16 17 int main() 18 { 19 printf( "Input the number of queens: " ); 20 scanf( "%d", &n ); 21 fp = fopen( "Result.txt", "w" ); 22 int index = 0; 23 if (n >= 4 && n <= 100) 24 PutQueen( index ); 25 else 26 printf( "Out of Range!\n" ); 27 fclose( fp ); 28 printf( "The %d queens puzzle has %d distinct solutions.\n", n, Result ); 29 return 0;
30 } 31 32 void OutPut() // Output to files 33 { 34 for (int i = 0; i < n; i++) 35 { 36 for (int j = 0; j < Queen[i]; j++) 37 fprintf( fp, " %d", 0 ); 38 fprintf( fp, " %d", 1 ); 39 for (int k = Queen[i] + 1; k < n; k++) 40 fprintf( fp, " %d", 0 ); 41 fprintf( fp, "\n" ); 42 } 43 fprintf( fp, "\n" ); 44 } 45 46 bool Attack( int index ) 47 { 48 for (int i = 0; i < index; i++) 49 if (Queen[i] == Queen[index] || PlusB[i] == PlusB[index] || MinusB[i] == MinusB[index]) 50 return true; 51 return false; 52 } 53 54 void PutQueen( int index ) 55 { 56 if (index == n) 57 { 58 Result++; 59 OutPut(); 60 return; 61 } 62 for (int i = 0; i < n; i++) 63 { 64 Queen[index] = i; 65 PlusB[index] = index - i; 66 MinusB[index] = index + i; 67 if (!Attack( index )) PutQueen( index + 1 ); 68 } 69 }