经典八皇后问题,主要用到的是递归回溯,网上小甲虫的源代码我没找到,这儿给贴一个吧。
//小甲虫数据结构之八皇后问题
#include <stdio.h>
#define CHESS_ROW 8 //棋盘行数
#define CHESS_COLUMN 8 //棋盘列数
int count=0;
int notDanger(int row, int j , int (*chess)[CHESS_COLUMN])
{
int i, k;
int flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;
//判断列方向是否有危险
for(i=0; i <CHESS_ROW; i++)
{
if(*(*(chess+i)+j)!=0)
{
flag1 = 1;
break;
// return 0;
}
}
//判断左上方
for(i=row, k=j; i>=0&&k>=0; i--,k--)
{
if(*(*(chess+i)+k)!=0)
{
flag2 = 1;
break;
//return 0;
}
}
//判断右下方
for(i=row, k=j; i<CHESS_ROW && k< CHESS_COLUMN ; i++,k++)
{
if(*(*(chess+i)+k)!=0)
{
flag3 = 1;
break;
//return 0;
}
}
//判断右上方
for(i=row, k=j; i>=0 && k<CHESS_COLUMN; i--,k++)
{
if(*(*(chess+i)+k)!=0)
{
flag4 = 1;
break;
// return 0;
}
}
//判断左下方
for(i=row, k=j; i<CHESS_ROW && k>=0; i++,k--)
{
if(*(*(chess+i)+k)!=0)
{
flag5 = 1;
break;
//return 0;
}
}
if(flag1|| flag2|| flag3 ||flag4 ||flag5)
return 0;
else
return 1;
}
// row:起始行
// n: 列数
// (*chess)[8] 棋盘中每行的向量
/*
* 八皇后递归算法,只使用了一个棋盘。
* 每次摆放到该行的最后一列时,
* 在返回上一行前先清空上一行上面
* 摆放的棋子。则不需要每次调换都
* 生成棋盘记录当前棋盘状况。
*/
void eightqueen(int row, int (*chess)[CHESS_COLUMN])
{
int chess2[CHESS_ROW][CHESS_COLUMN];
int i, j, flag;
for(i=0;i<8;i++)//初始化棋盘
for(j=0;j<8;j++)
chess2[i][j] = chess[i][j];
if(CHESS_ROW == row)
{
printf("第%2d次的结果是:\n", count+1);
for(i=0;i<CHESS_ROW;i++)//输出棋盘
{
for(j=0;j<CHESS_COLUMN;j++)
printf("%d ",*(*(chess2+i)+j));
printf("\n");
}
count++;
return;
}
else
{
for(j=0; j<CHESS_COLUMN; j++)
{
flag = notDanger(row, j , chess2);
if(1==flag)
{
for(i=0; i<8; i++)
*(*(chess2+row)+i) = 0;
*(*(chess2+row)+j) = 1;
eightqueen(row+1, chess2);
}
}
}
}
void main(void)
{
int chess[CHESS_ROW][CHESS_COLUMN];
int i, j;
for (i = 0; i < CHESS_ROW; i++) {
for (j = 0; j < CHESS_COLUMN; j++) {
chess[i][j] = 0;
}
}
eightqueen(0, chess);
return;
}
答案已经说了,92种,不过好像由于缓冲区的原因,所有的排列不能一次性显示,所以想看过程的可以单步调试。
在调用eightqueen的时候会重新建立一个数组,对递归来说,这样会很占内存,稍后会补充改进的方法。
//方法two
void eightqueen(int row, int (*chess2)[CHESS_COLUMN])
{
// int chess2[CHESS_ROW][CHESS_COLUMN];
int i, j, flag;
/* for(i=0;i<8;i++)//初始化棋盘
for(j=0;j<8;j++)
chess2[i][j] = chess[i][j];
*/
if(CHESS_ROW == row)
{
printf("第%2d次的结果是:\n", count+1);
for(i=0;i<CHESS_ROW;i++)//输出棋盘
{
for(j=0;j<CHESS_COLUMN;j++)
printf("%d ",*(*(chess2+i)+j));
printf("\n");
}
count++;
//对本行进行清空
for(i=0; i<8; i++)
*(*(chess2+row-1)+i) = 0;
return;
}
else
{
for(j=0; j<CHESS_COLUMN; j++)
{
flag = notDanger(row, j , chess2);
if(1==flag)
{
for(i=0; i<8; i++)
*(*(chess2+row)+i) = 0;
*(*(chess2+row)+j) = 1;
eightqueen(row+1, chess2);
}
}
}
// 遍历完这一行(参数row)之后, 对这一行进行清空
// 这段代码可以对chess进行逐行的清空
// 上面的代码只是对8-1行进行了清空,而外层的循环进行的时候(比如调用row行的时候)
//在调用完之后,chess中的第row行是有数据的,所以要把这行清空才能用于后面判断其他位置是否有效
if (row > 0)
{ //没有到首行,则清空上一行
for(i=0; i<8; i++)
*(*(chess2+row-1)+i) = 0;
}
}