会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将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--; //还原,继续探索本行的下一个点
}
}
}