回溯算法 - 八皇后问题找所有解递归和非递归

八皇后问题描述

1.什么是八皇后问题

在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

即在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上
在这里插入图片描述

解析算法:

    1.首先我们并不需要一开始就接设计8x8的二维数组(这个二维数组只是比较好说明问题。),如果我们以行移动为基准的话,我们只要统计该行的每一列,以及它的左斜线和它的右斜线能否放皇后就可以了。
    2.所以我们只需要3个数组分别代表就行了。这里肯定有人说列用数组好代表,那左斜线和右斜线该用数组怎么表示呢!其实我们不难发现,左斜线的值得规律为它得i+j=7(行加列的值),右斜线的规律为i-j+7
备注 i为行,j为列,左斜线有15条,右斜线也有15条。因为是8 x 8的矩阵
画个图一下就明白了。

if((!col[j])&&(!left[i+j])&&(!right[i-j+7]))  //判段能否放皇后 

递归

#include<stdio.h>
#include  <conio.h>
int count=0; //计数,一共有多少组合 
int col[8]={0},right[15]={0},left[15]={0};//col列数,left左斜线 right 右斜线,
	int q[8]={0}; 	 
	
	
void print(){
	printf("=======================\n\n");
	for(int t=0;t<8;t++){
		printf("%d行%d列\n",t,q[t]);
	}
	count++;
	//printf("=======================");
}	
	
void queen(int i){
	int j;
	for(j=0;j<8;++j){
		if((!col[j])&&(!left[i+j])&&(!right[i-j+7])){  //判段能否放皇后 
			col[j]=left[i+j]=right[i-j+7]=1;		//修改列值和左斜线 右斜线	
														//修改 col列数,left左斜线 right 右斜线的值 置1 
			q[i]=j;					//q[i]下标为行,存储的值为列 
			if(i<7){                  //判断行数是否到达第七行,如果到达第七行,超过直接输出 
				queen(i+1);	 //回溯到下一行						
			}
			else{
			//进入else无非就是到了第七行                     
				print();
			}
			col[j]=left[i+j]=right[i-j+7]=0;//抹皇后 两种情况  1.该行放不了回溯到上一层,上一层皇后放的有问题2.到达第七行 
		}
	}
}


int main(){
	queen(0);
	
	printf("count = %d\n",count);
}


非递归

#include<stdio.h>
#include  <conio.h>
int count=0; //计数,一共有多少组合 
int col[8]={0},right[15]={0},left[15]={0};//col列数,left左斜线 right 右斜线,
	int q[8]={0};//存储皇后的数组 
	
	
void print(){
	printf("=======================\n\n");
	for(int t=0;t<8;t++){
		printf("%d行%d列\n",t,q[t]);
	}
	count++;
	printf("count=%d",count);

}

int main(){
	int i=0,j=0;
	while(i<8){
		//@ 1 
		while(j<8){
			//@2 
			if((!col[j])&&(!left[i+j])&&(!right[i-j+7]))   //判段能否放皇后 
				break;  //从break跳出 找到满足条件的皇后  
				j++;
		//如果循环了8次还没找到,就说明上一个的皇后有问题		
		}
		if(j<8){
			//从break跳转出来 	
			col[j]=left[i+j]=right[i-j+7]=1; 	//修改列值和左斜线 右斜线	
			q[i]=j;                   //存皇后         
				if(i<7){
					//@3  进入下一行,这个时候注意列值要从头开始 
					j=0;
					i++;
				}
				else{
					//行数已经到达第七行
					print();  //  输出 
					col[j]=left[i+j]=right[i-j+7]=0; //抹皇后,继续查找 
					j++;  //从第7行被抹皇后的后面继续查找 
				}
		}
		else{
			//这个时候j是正常跳转出来,循环完毕 
			//当前行放不了,回到上一行 
				i--;  //回到上一行 
				j=q[i];  //j保存上一行中的皇后的列数
				col[j]=left[i+j]=right[i-j+7]=0; //抹皇后 
				j++;  // 从错误的皇后列数,继续往后找
			//注意:这里一定是先要抹皇后,在往后找。如果先往后面找的话,抹皇后就出现了问题。 
			}
		}

	}



 

一共92中解。这里非递归出现了问题,我尝试在main函数里输出count总数,但就是输出不出来,于是我只能转入输出函数中,输出每一中结果。
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值