1、递归。递归真是个好东西,解法一目了然。
#include
#define N 8
int l[14];
int r[14];
int q[N];
int col[N];
static int cnt = 0;
void try(int i)
{
int j;
for(j=0; j
{
if(l[i+j] == 0 && r[i-j+7] ==0 && col[j] == 0)
{
l[i+j]=1;
r[i-j+7] =1;
col[j] = 1;
q[i] = j;
if(i+1 == N)
{
++cnt;
// return;
}
else
{
try(i+1);
}
l[i+j] = 0;
r[i-j+7] = 0;
col[j] = 0;
q[i] = -1;
}
}
}
int main()
{
int i;
for(i=0; i<14; i++)
{
l[i] = 0;
r[i] = 0;
}
for(i = 0; i
{
col[i] = 0;
q[i] = -1;
}
try(0);
printf("cnt = %d\n", cnt);
return 0;
}
2、非递归解
#include
#define QUEEN 8 //皇后数量
int queen[QUEEN] ; //下标代表所在列号,值代表所在行号,
//如queen[1]=2表示第1列第2行有个皇后
bool col_YN[QUEEN] ; //棋局的每一行是否有棋,有则为1,无为0 ;
bool passive_YN[2*QUEEN-1] ; //斜率为1的斜线方向上是否有棋,共有2*QUEEN-1个斜线
bool negative_YN[2*QUEEN-1] ; //斜率为负1的斜线方向上是否有棋
//用全局变量,因全局数组元素值自动为0
int main()
{
int col = 0 ;//游标,当前移动的棋子(以列计)
bool flag = false ; //当前棋子位置是否合法
queen[0] = -1 ; //第0列棋子准备,因一开始移动的就是第0列棋子
int count = 0 ; //一共有多少种解法的计数器 ;
while(col>=0 ) //跳出条件是回溯到无法回溯时
{
queen[col]++ ; //col列上的皇后走到下一行试试
if(queen[col] >= QUEEN) //当前列全部走完
{
queen[col] = -1 ; //当前列棋子置于准备状态
col-- ; //回溯到上一列的棋子
if(col>=0) //回溯时要清理如下行,斜线的标志位
{
col_YN[queen[col]] = false ;
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;
}
}
else
{
//先判断棋子所在行没有棋子
if(col_YN[queen[col]] == false)
{
flag = true ;
//以下检查当前棋子是否与之前的棋子斜线相交
if( passive_YN[queen[col] + col] == true || negative_YN[QUEEN-1 + col - queen[col]] == true)
flag = false ;
else
flag = true ;
if(flag) // flag为真表示位置合法
{
if(col == QUEEN-1) //列到达最后,即最后一个皇后也找到位置,输出解
{
count++ ; //解法的数目加一 ;
cout<
for(int i=0;i
cout<
}
col_YN[queen[col]] = true ;// 当前行设为有棋子
passive_YN[queen[col] + col] = true ;//当前行正斜率方向有棋子
negative_YN[QUEEN-1 + col - queen[col]] = true ; //当前行负斜率方向 上也有棋子
col++ ;
if(col >= QUEEN)
{ // 找到解后再次回溯找另外的解,这同上面无解回溯是一样的
col-- ;
col_YN[queen[col]] = false ;
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;//原理同回溯
}
flag = false ;
}
}
}
}
cout<
return 0 ;
}
八皇后问题的实现(C语言)
2008-01-05 20:41
八皇后问题主要靠回溯的方法实现, 与迷宫的实现相似, 但又困难了一些. 如迷宫的路径不因为上一步而改变, 八皇后的每一步都受约束于以前的步数, 并且, 迷宫只要找出一条路径就行,但八皇后则有很多的解法. 等等.
#include
#define N 8 // 定义棋盘的格数, 通过改变,也可以是4皇后, 16皇后, 9皇后什么的.
int chess[N][N] = {0}; // 棋盘
int count = 0; // 有多少种放法
int canput(int row, int col) // 确定某一格能不能放
{
int i,j;
for(i = 0; i < N; i ++)
{
if(chess[i][col] == 1) //有 同列的
{
return 0;
}
for(j = 0; j < N; j++)
{
if(chess[row][j]==1) //有同行的
{
return 0;
}
if(((i-row)==(j-col)||(i-row)==(col-j))&&chess[i][j]==1) // 对角线上有的
{
return 0;
}
}
}
return 1;
}
void print_chess() // 打印放置的方案
{
int i, j;
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
printf("%d ", chess[i][j]);
}
printf("\n");
}
printf("\n");
}
int put(int row) // 放置棋子, row是从哪一行开始, 通常是0
{
int j, s;
for(j = 0; j < N; j++) // 此一行的每一个格子都要试试能不能放
{
if(canput(row, j)) // 假如这格能放的话
{
chess[row][j] = 1; // 放置
if(row == N-1) // 已经到了最后一行, 那么肯定成功******************************************************
{
count = count +1;
print_chess();
chess[row][j] = 0; //成功后, 寻找下一种方法
continue;
}
s = put(row+1); // 放置下一行的
if(s == 0) // 假如下一行不能放
{
chess[row][j] = 0; // 那么这格是放错了的, 清除
continue; // 找本行的下一个方格
}
else
{
break;
}
}
}
if(j==N) // 如果这一行的每个空格都不能放置
{
return 0; // 那么本行放置失败
}
else
{
return 1; // 本行放置成功
}
}
int main()
{
int s ;
s = put(0); // 放置
printf("the number of put way is %d\n", count); //打印信息
return 0;
}
这个程序有个奇怪的地方, 就是在有星号的那一行, 当把chess[row][j] = 0, continue;两句去掉时,发现程序依然能正常运行. 原因就是: 当行比列多时, 假如皇后是的数目是列那么多, 是肯定放不成功的, 所以, 当程序要在最后一行的下一行放皇后时,怎么放也不成功,所以, 程序会不断调整以前的方法,但打印信息却在这里执行, 所以能打出正确信息. 但不建议去掉, 因为操作未知内存终究不是件好事.