问题描述:
在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 }