利用回溯法解决这个问题:
回溯算法的基本思想是:从一条往前走,能进则进,不能进则退回来,换一条路再试。
书面一点:从问题的某一种状态出发,搜索可以到达的所有状态;
当某个状态到达后(即满足了要求) 或者该状态不符合要求,可向前回退,并继续搜索其他可达到的状态;
当所有状态都到达后,回溯算法结束。
算法解决思路:
1.初始化: i = 1; //行
2.初始化: j = 1; //列
3. 从第i行开始,恢复j的当前值,判断第j个位置:
a、 位置j可放入皇后:标记位置(i,j),i++, 执行步骤2
b、 位置j不可放入皇后:j++,执行步骤a;
c、 当j>8时,i--(回溯),执行步骤3。
4. 结束: 当第8行可以放入皇后。
程序代码:
#include <stdio.h> #define N 8 typedef struct Pos //记录偏移量 { int i; int j; }Pos; static char board[N+2][N+2]; //增加边界,方便递归使用 static Pos pos[] = {{-1, -1}, {-1, 0}, {-1, 1}}; //正对角线上,每一列上, 斜对角线上的偏移量 static int count = 0; //统计多少中放法; /** * 初始化数组,边界上的值用'#'表示, 其余数值用' '表示 **/ void init() { int i = 0; //行 int j = 0; //列 for(i=0; i < N+2; i++) { board[0][i] = '#'; board[N+1][i] = '#'; board[i][0] = '#'; board[i][N+1] = '#'; } for(i=1; i<=N; i++) { for(j=1; j<=N; j++) { board[i][j] = ' '; } } } /** * 显示摆放结果 **/ void display() { int i = 0; int j = 0; for(i=0; i<N+2; i++) { for(j=0; j<N+2; j++) { printf("%c", board[i][j]); } printf("\n"); } } /** * 检测第i行j列上摆放一个女皇是否符合要求 **/ int check(int i, int j) { int ret = 1; //返回值 int p = 0; for(p=0; p<3; p++) //开始在正对角线,列,斜对角线上分别进行检测 { int ni = i; int nj = j; while(ret && (board[ni][nj] != '#')) { ni = ni + pos[p].i; //坐标偏移量 nj = nj + pos[p].j; ret = ret && (board[ni][nj] != 'K'); } } return ret; } /** *查找第i行摆放女皇的情况 **/ void find(int i) { int j = 0; //如果i已经超出第8行,则表示摆放已经完毕,直接显示摆放结果 if(i > N) { count++; printf("total: %d\n", count); display(); //getchar(); } else //还没有摆放结束 { for(j=1; j<=N; j++) { //检测(i,j)位置处是否可以摆放 if(check(i, j)) { board[i][j] = 'K'; find(i+1); //继续查找下一行的摆放情况 //find(i+1)没有找到正确的摆放状态,回溯到前一状态,然后继续检测(i, j+1)处的摆放是否合法 // 或者find(i+1)正确找到了摆放状态,并且已经打印出摆放结果,下面要继续查找另一种摆放方法(i, j+1)是否可行,所以也要回溯到上一状态 board[i][j] = ' '; } } } } int main() { init(); find(1); return 0; }