递归与回溯:
递归在程序设计中经常用于回溯算法的场合;
回溯算法的基本思想:
1,从问题的某一状态出发,搜索可以达到的所有状态;
2.当某个状态到达后,可向前后退,并可继续查找其他状态;
3.当所有状态都到达后,回溯算法结束;
程序设计中可以利用函数的活动对象保存回溯算法的状态数据,因此可以利用递归完成回溯算法;
八皇后问题:
任意位置,判断放皇后的三个方向,用偏移量{-1,-1},{-1,0},{-1,1}来操作。
#include <stdio.h>
#define N 8
typedef struct _tag_Pos//偏移结构体
{
int ios;//i的偏移量
int jos;//j的偏移量
} Pos;
static char board[N+2][N+2];//边界10*10
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++)//国际象棋棋盘8*8,特别注意此处i,j初始值均为1
{
for(j=1; j<=N; j++)
{
board[i][j] = ' ';
}
}
}
void display()//打印二维数组,判断棋盘是否为我们想要的棋盘
{
int i = 0;
int j = 1;
for(i=0; i<N+2; i++)
{
for(j=0; j<N+2; j++)
{
printf("%c", board[i][j]);
}
printf("\n");
}
}
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].ios;
nj = nj + pos[p].jos;
ret = ret && (board[ni][nj] != '*');//表示方向没有皇后,*表示皇后
}
}
return ret;
}
void find(int i)//按行查找
{
int j = 0;
if( i > N )//达到第八行
{
count++;//意味着找到了结果
printf("Solution: %d\n", count);
display();//打印结果
getchar();//执行暂停
}
else
{
for(j=1; j<=N; j++)
{
if( check(i, j) )//如果当前位置可以放皇后
{
board[i][j] = '*';
find(i+1);//查找下一行
board[i][j] = ' ';//清空,回朔
}
}
}
}
int main()
{
init();
find(1);
return 0;
}
回溯算法是递归应用的重要场合,利用函数的活动对象可以保存回溯算法中的重要变量信息,递归是回溯算法的重要实现方式!