递归、回溯-八皇后问题

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83048466

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法.

输入:无

输出:8行8列的矩阵,0代表此处无皇后,1表示此处有皇后。

运行结果(由于解太多了,只放两个解吧):

算法实现:

逐行处理当前编号i的行。目标是每一行都放一个皇后。

Status Go(int a[N][N],int i){//逐行处理当前编号i的行
   int j,successFlag;
   for(j=0;j<N;j++){
      a[i][j]=1;//尝试在第i行第j列放皇后
      successFlag=Verify(a,i,j);
      if(!successFlag){//不能放皇后
         a[i][j]=0;
         continue;
      }
      else if(successFlag&&i==N-1){//边界 验证合法到结束i=N-1
        PrintChessBoard(a);//保存解
        a[i][j]=0;
        continue;
      }
      else if(successFlag&&i<N-1){
        Go(a,i+1);//递归前进 合法从下一行开始递归
        a[i][j]=0;//不管成功与否都重置
        continue;
      }
   }
}

如何判断此处是否可以放皇后呢?判断一列中有两个皇后很简单,循环一遍统计着这一列皇后的数目就可以了。如何找到其左对角线与右对角线上的皇后呢?

我们可以通过一个规律来解决。我们可以发现,当皇后在(i,j)位置时,如果其左对角线上坐标为(x,y)就会满足表达式:

i-j = x-y

同过这个表达式可以判断一个位置是否位于皇后位置的左对角线上。同理,右对角线表达式为:

i-x = y-j;

判断是否可以放皇后 可以返回1 否则返回0

i将要行 j将要放置的列.

int  Verify(int a[N][N],int i,int j){//i将要行 j1将要放置的列
    //判断是否可以放皇后 可以返回1 否则返回0
    int sum,x,y;
    for(y=0;y<N;y++)
    {//逐列检查
    sum=0;
    for(x=0;x<=i;x++)
        sum+=a[x][y];
    if(sum > 1)
        return 0;
    sum = 0;
    for(x=0;x<i;x++)
    {
        if(x-y==i-j) //在其左对角线上
            sum+=a[x][y];
        if(i-x==y-j) //在其右对角线上
            sum+=a[x][y];
    }
    if(sum > 0)
        return 0;
   }
   return 1;
}

输出棋盘.

void PrintChessBoard(int a[N][N]){
	//输出棋盘
	num++;
	int i,j;
	for(i=0;i<N;i++){
		for(j=0;j<N;j++){
			printf("%3d",a[i][j]);
		}
		printf("\n");
	}
	printf("\n\n");
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83048466