ACM八皇后详解
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。
思路:
要求在8*8的方格中放置8个皇后。稍加分析知道,必定是每行放一个。
采用回溯算法。从第一行开始。依次遍历8列。检查该点是否可以放置皇后。如果可以放置,放置完成后,直接递归到下一行。继续以相同的方式检查。函数回溯的时候有两种情况。
- 由于前面错误的放法,导致本行没有可以放置的点。
- 八行已经全部放完。此时已经求出一个解。
上述两种情况都需要在回溯后,还原放置的点。
理由:
- 错误的放置导致的返回,所以这个点是错误的,不能放置,还原后继续试探本行的下一个点。
2.八行已经放完时,还原这个点看看还有没有别的放法。
下面给出代码
int arr[8][8]; int sum = 0; //每个点检查的八个方向 int dir[8][2] = { {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1} }; void PPmatrix(int *name, int H, int L); int check(int x, int y); void dfs(int xy, int num); int main(int argc, char *argv[]) { dfs(0, 0); printf("sum = %d\n", sum); return 0; } void PPmatrix(int *name, int H, int L) { int i = 0; int j = 0; for(i = 0; i < H; i++) { for(j = 0; j < L; j++) { printf("%d ", *(name++)); } putchar('\n'); } putchar('\n'); } int check(int x, int y) { int x1 = x, y1 = y; int i; for(i = 0; i < 8; i++) //八个方向检查 { x1 = x; y1 = y; while(x1 >= 0 && x1 < 8 && y1 >= 0 && y1 < 8) { if(arr[x1][y1] != 0) return 0; x1 += dir[i][0]; y1 += dir[i][1]; } } return 1; } void dfs(int xy, int num) { int i; if(num >= 8) //已经找到一中解法 { PPmatrix(&arr[0][0], 8, 8); sum++; return; } for(i = 0; i < 8; i++) { int ch = check(xy, i); //检查当前点是否可以放置 if(ch == 1) { arr[xy][i] = 1; //可以的话放置 num++; dfs(xy+1, num); //继续在下一行试探 arr[xy][i] = 0; //回溯,有两种情况,根据分析,两种情况都需要还原 num--; //还原,继续探索本行的下一个点 } } }